From 465ac74020850bb88300d9d89d3cea91307fdd30 Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Tue, 11 Jun 2024 18:19:16 +0200 Subject: [PATCH 001/122] more windows stuff --- core/sys/windows/advapi32.odin | 37 ++++ core/sys/windows/codepage.odin | 298 +++++++++++++++++++++++++++ core/sys/windows/gdi32.odin | 363 ++++++++++++++++++++++++++------- core/sys/windows/kernel32.odin | 49 ++++- core/sys/windows/ole32.odin | 16 +- core/sys/windows/shcore.odin | 25 +++ core/sys/windows/shell32.odin | 2 + core/sys/windows/types.odin | 120 ++++++++++- core/sys/windows/user32.odin | 269 ++++++++++++++++++------ core/sys/windows/util.odin | 61 +++++- core/sys/windows/winerror.odin | 230 ++++++++++++++++++++- core/sys/windows/winmm.odin | 17 +- core/sys/windows/winnls.odin | 31 +++ core/sys/windows/winver.odin | 92 +++++++++ 14 files changed, 1457 insertions(+), 153 deletions(-) create mode 100644 core/sys/windows/codepage.odin create mode 100644 core/sys/windows/shcore.odin create mode 100644 core/sys/windows/winnls.odin create mode 100644 core/sys/windows/winver.odin diff --git a/core/sys/windows/advapi32.odin b/core/sys/windows/advapi32.odin index 163bf2a5e..1e8060b3f 100644 --- a/core/sys/windows/advapi32.odin +++ b/core/sys/windows/advapi32.odin @@ -134,6 +134,43 @@ foreign advapi32 { cbData: DWORD, ) -> LSTATUS --- + RegQueryInfoKeyW :: proc( + hKey: HKEY, + lpClass: LPWSTR, + lpcchClass: LPDWORD, + lpReserved: LPDWORD, + lpcSubKeys: LPDWORD, + lpcbMaxSubKeyLen: LPDWORD, + lpcbMaxClassLen: LPDWORD, + lpcValues: LPDWORD, + lpcbMaxValueNameLen: LPDWORD, + lpcbMaxValueLen: LPDWORD, + lpcbSecurityDescriptor: LPDWORD, + lpftLastWriteTime: ^FILETIME, + ) -> LSTATUS --- + + RegEnumKeyExW :: proc( + hKey: HKEY, + dwIndex: DWORD, + lpName: LPWSTR, + lpcchName: LPDWORD, + lpReserved: LPDWORD, + lpClass: LPWSTR, + lpcchClass: LPDWORD, + lpftLastWriteTime: ^FILETIME, + ) -> LSTATUS --- + + RegEnumValueW :: proc( + hKey: HKEY, + dwIndex: DWORD, + lpValueName: LPWSTR, + lpcchValueName: LPDWORD, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD, + ) -> LSTATUS --- + GetFileSecurityW :: proc( lpFileName: LPCWSTR, RequestedInformation: SECURITY_INFORMATION, diff --git a/core/sys/windows/codepage.odin b/core/sys/windows/codepage.odin new file mode 100644 index 000000000..90040f1ee --- /dev/null +++ b/core/sys/windows/codepage.odin @@ -0,0 +1,298 @@ +// +build windows +package sys_windows + +// https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers +CODEPAGE :: enum UINT { + // Default to ANSI code page + ACP = CP_ACP, + // Default to OEM code page + OEMCP = CP_OEMCP, + // Default to MAC code page + MACCP = CP_MACCP, + // Current thread's ANSI code page + THREAD_ACP = CP_THREAD_ACP, + // Symbol translations + SYMBOL = CP_SYMBOL, + + // IBM EBCDIC US-Canada + IBM037 = 037, + // OEM United States + IBM437 = 437, + // IBM EBCDIC International + IBM500 = 500, + // Arabic (ASMO 708) + ASMO_708 = 708, + // Arabic (Transparent ASMO); Arabic (DOS) + DOS_720 = 720, + // OEM Greek (formerly 437G); Greek (DOS) + IBM737 = 737, + // OEM Baltic; Baltic (DOS) + IBM775 = 775, + // OEM Multilingual Latin 1; Western European (DOS) + IBM850 = 850, + // OEM Latin 2; Central European (DOS) + IBM852 = 852, + // OEM Cyrillic (primarily Russian) + IBM855 = 855, + // OEM Turkish; Turkish (DOS) + IBM857 = 857, + // OEM Multilingual Latin 1 + Euro symbol + IBM00858 = 858, + // OEM Portuguese; Portuguese (DOS) + IBM860 = 860, + // OEM Icelandic; Icelandic (DOS) + IBM861 = 861, + // OEM Hebrew; Hebrew (DOS) + DOS_862 = 862, + // OEM French Canadian; French Canadian (DOS) + IBM863 = 863, + // OEM Arabic; Arabic (864) + IBM864 = 864, + // OEM Nordic; Nordic (DOS) + IBM865 = 865, + // OEM Russian; Cyrillic (DOS) + CP866 = 866, + // OEM Modern Greek; Greek, Modern (DOS) + IBM869 = 869, + // IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 + IBM870 = 870, + // Thai (Windows) + WINDOWS_874 = 874, + // IBM EBCDIC Greek Modern + CP875 = 875, + // ANSI/OEM Japanese; Japanese (Shift-JIS) + SHIFT_JIS = 932, + // ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) + GB2312 = 936, + // ANSI/OEM Korean (Unified Hangul Code) + KS_C_5601_1987 = 949, + // ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) + BIG5 = 950, + // IBM EBCDIC Turkish (Latin 5) + IBM1026 = 1026, + // IBM EBCDIC Latin 1/Open System + IBM01047 = 1047, + // IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) + IBM01140 = 1140, + // IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) + IBM01141 = 1141, + // IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) + IBM01142 = 1142, + // IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) + IBM01143 = 1143, + // IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) + IBM01144 = 1144, + // IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) + IBM01145 = 1145, + // IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) + IBM01146 = 1146, + // IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) + IBM01147 = 1147, + // IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) + IBM01148 = 1148, + // IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) + IBM01149 = 1149, + // Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications + UTF16 = 1200, + // Unicode UTF-16, big endian byte order; available only to managed applications + UNICODEFFFE = 1201, + // ANSI Central European; Central European (Windows) + WINDOWS_1250 = 1250, + // ANSI Cyrillic; Cyrillic (Windows) + WINDOWS_1251 = 1251, + // ANSI Latin 1; Western European (Windows) + WINDOWS_1252 = 1252, + // ANSI Greek; Greek (Windows) + WINDOWS_1253 = 1253, + // ANSI Turkish; Turkish (Windows) + WINDOWS_1254 = 1254, + // ANSI Hebrew; Hebrew (Windows) + WINDOWS_1255 = 1255, + // ANSI Arabic; Arabic (Windows) + WINDOWS_1256 = 1256, + // ANSI Baltic; Baltic (Windows) + WINDOWS_1257 = 1257, + // ANSI/OEM Vietnamese; Vietnamese (Windows) + WINDOWS_1258 = 1258, + // Korean (Johab) + JOHAB = 1361, + // MAC Roman; Western European (Mac) + MACINTOSH = 10000, + // Japanese (Mac) + X_MAC_JAPANESE = 10001, + // MAC Traditional Chinese (Big5); Chinese Traditional (Mac) + X_MAC_CHINESETRAD = 10002, + // Korean (Mac) + X_MAC_KOREAN = 10003, + // Arabic (Mac) + X_MAC_ARABIC = 10004, + // Hebrew (Mac) + X_MAC_HEBREW = 10005, + // Greek (Mac) + X_MAC_GREEK = 10006, + // Cyrillic (Mac) + X_MAC_CYRILLIC = 10007, + // MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) + X_MAC_CHINESESIMP = 10008, + // Romanian (Mac) + X_MAC_ROMANIAN = 10010, + // Ukrainian (Mac) + X_MAC_UKRAINIAN = 10017, + // Thai (Mac) + X_MAC_THAI = 10021, + // MAC Latin 2; Central European (Mac) + X_MAC_CE = 10029, + // Icelandic (Mac) + X_MAC_ICELANDIC = 10079, + // Turkish (Mac) + X_MAC_TURKISH = 10081, + // Croatian (Mac) + X_MAC_CROATIAN = 10082, + // Unicode UTF-32, little endian byte order; available only to managed applications + UTF32 = 12000, + // Unicode UTF-32, big endian byte order; available only to managed applications + UTF32BE = 12001, + // CNS Taiwan; Chinese Traditional (CNS) + X_CHINESE_CNS = 20000, + // TCA Taiwan + X_CP20001 = 20001, + // Eten Taiwan; Chinese Traditional (Eten) + X_CHINESE_ETEN = 20002, + // IBM5550 Taiwan + X_CP20003 = 20003, + // TeleText Taiwan + X_CP20004 = 20004, + // Wang Taiwan + X_CP20005 = 20005, + // IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) + X_IA5 = 20105, + // IA5 German (7-bit) + X_IA5_GERMAN = 20106, + // IA5 Swedish (7-bit) + X_IA5_SWEDISH = 20107, + // IA5 Norwegian (7-bit) + X_IA5_NORWEGIAN = 20108, + // US-ASCII (7-bit) + US_ASCII = 20127, + // T.61 + X_CP20261 = 20261, + // ISO 6937 Non-Spacing Accent + X_CP20269 = 20269, + // IBM EBCDIC Germany + IBM273 = 20273, + // IBM EBCDIC Denmark-Norway + IBM277 = 20277, + // IBM EBCDIC Finland-Sweden + IBM278 = 20278, + // IBM EBCDIC Italy + IBM280 = 20280, + // IBM EBCDIC Latin America-Spain + IBM284 = 20284, + // IBM EBCDIC United Kingdom + IBM285 = 20285, + // IBM EBCDIC Japanese Katakana Extended + IBM290 = 20290, + // IBM EBCDIC France + IBM297 = 20297, + // IBM EBCDIC Arabic + IBM420 = 20420, + // IBM EBCDIC Greek + IBM423 = 20423, + // IBM EBCDIC Hebrew + IBM424 = 20424, + // IBM EBCDIC Korean Extended + X_EBCDIC_KOREANEXTENDED = 20833, + // IBM EBCDIC Thai + IBM_THAI = 20838, + // Russian (KOI8-R); Cyrillic (KOI8-R) + KOI8_R = 20866, + // IBM EBCDIC Icelandic + IBM871 = 20871, + // IBM EBCDIC Cyrillic Russian + IBM880 = 20880, + // IBM EBCDIC Turkish + IBM905 = 20905, + // IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) + IBM00924 = 20924, + // Japanese (JIS 0208-1990 and 0212-1990) + EUC_JP = 20932, + // Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) + X_CP20936 = 20936, + // Korean Wansung + X_CP20949 = 20949, + // IBM EBCDIC Cyrillic Serbian-Bulgarian + CP1025 = 21025, + // Ukrainian (KOI8-U); Cyrillic (KOI8-U) + KOI8_U = 21866, + // ISO 8859-1 Latin 1; Western European (ISO) + ISO_8859_1 = 28591, + // ISO 8859-2 Central European; Central European (ISO) + ISO_8859_2 = 28592, + // ISO 8859-3 Latin 3 + ISO_8859_3 = 28593, + // ISO 8859-4 Baltic + ISO_8859_4 = 28594, + // ISO 8859-5 Cyrillic + ISO_8859_5 = 28595, + // ISO 8859-6 Arabic + ISO_8859_6 = 28596, + // ISO 8859-7 Greek + ISO_8859_7 = 28597, + // ISO 8859-8 Hebrew; Hebrew (ISO-Visual) + ISO_8859_8 = 28598, + // ISO 8859-9 Turkish + ISO_8859_9 = 28599, + // ISO 8859-13 Estonian + ISO_8859_13 = 28603, + // ISO 8859-15 Latin 9 + ISO_8859_15 = 28605, + // Europa 3 + X_EUROPA = 29001, + // ISO 8859-8 Hebrew; Hebrew (ISO-Logical) + ISO_8859_8_I = 38598, + // ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) + ISO_2022_JP = 50220, + // ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) + CSISO2022JP = 50221, + // ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) + ISO_2022_2_JP = 50222, + // ISO 2022 Korean + ISO_2022_KR = 50225, + // ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) + X_CP50227 = 50227, + // EUC Japanese + EUC_JP_2 = 51932, + // EUC Simplified Chinese; Chinese Simplified (EUC) + EUC_CN = 51936, + // EUC Korean + EUC_KR = 51949, + // HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) + HZ_GB_2312 = 52936, + // **Windows XP and later:** GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) + GB18030 = 54936, + // ISCII Devanagari + X_ISCII_DE = 57002, + // ISCII Bangla + X_ISCII_BE = 57003, + // ISCII Tamil + X_ISCII_TA = 57004, + // ISCII Telugu + X_ISCII_TE = 57005, + // ISCII Assamese + X_ISCII_AS = 57006, + // ISCII Odia + X_ISCII_OR = 57007, + // ISCII Kannada + X_ISCII_KA = 57008, + // ISCII Malayalam + X_ISCII_MA = 57009, + // ISCII Gujarati + X_ISCII_GU = 57010, + // ISCII Punjabi + X_ISCII_PA = 57011, + + // Unicode (UTF-7) + UTF7 = CP_UTF7, /*65000*/ + // Unicode (UTF-8) + UTF8 = CP_UTF8, /*65001*/ +} diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index 6d53845de..6c7eda03d 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -7,108 +7,97 @@ foreign import gdi32 "system:Gdi32.lib" @(default_calling_convention="system") foreign gdi32 { - GetStockObject :: proc(i: c_int) -> HGDIOBJ --- + GetDeviceCaps :: proc(hdc: HDC, index: INT) -> INT --- + GetStockObject :: proc(i: INT) -> HGDIOBJ --- SelectObject :: proc(hdc: HDC, h: HGDIOBJ) -> HGDIOBJ --- DeleteObject :: proc(ho: HGDIOBJ) -> BOOL --- SetBkColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- + SetBkMode :: proc(hdc: HDC, mode: BKMODE) -> INT --- CreateCompatibleDC :: proc(hdc: HDC) -> HDC --- DeleteDC :: proc(hdc: HDC) -> BOOL --- + CancelDC :: proc(hdc: HDC) -> BOOL --- + SaveDC :: proc(hdc: HDC) -> INT --- + RestoreDC :: proc(hdc: HDC, nSavedDC: INT) -> BOOL --- CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH --- + CreateDIBitmap :: proc(hdc: HDC, pbmih: ^BITMAPINFOHEADER, flInit: DWORD, pjBits: VOID, pbmi: ^BITMAPINFO, iUsage: UINT) -> HBITMAP --- + CreateDIBSection :: proc(hdc: HDC, pbmi: ^BITMAPINFO, usage: UINT, ppvBits: VOID, hSection: HANDLE, offset: DWORD) -> HBITMAP --- + StretchDIBits :: proc(hdc: HDC, xDest: INT, yDest: INT, DestWidth: INT, DestHeight: INT, xSrc: INT, ySrc: INT, SrcWidth: INT, SrcHeight: INT, lpBits: VOID, lpbmi: ^BITMAPINFO, iUsage: UINT, rop: DWORD) -> INT --- + StretchBlt :: proc(hdcDest: HDC, xDest: INT, yDest: INT, wDest: INT, hDest: INT, hdcSrc: HDC, xSrc: INT, ySrc: INT, wSrc: INT, hSrc: INT, rop: DWORD) -> BOOL --- - CreateDIBitmap :: proc( - hdc: HDC, - pbmih: ^BITMAPINFOHEADER, - flInit: DWORD, - pjBits: VOID, - pbmi: ^BITMAPINFO, - iUsage: UINT, - ) -> HBITMAP --- - - CreateDIBSection :: proc( - hdc: HDC, - pbmi: ^BITMAPINFO, - usage: UINT, - ppvBits: VOID, - hSection: HANDLE, - offset: DWORD, - ) -> HBITMAP --- - - StretchDIBits :: proc( - hdc: HDC, - xDest: c_int, - yDest: c_int, - DestWidth: c_int, - DestHeight: c_int, - xSrc: c_int, - ySrc: c_int, - SrcWidth: c_int, - SrcHeight: c_int, - lpBits: VOID, - lpbmi: ^BITMAPINFO, - iUsage: UINT, - rop: DWORD, - ) -> c_int --- - - StretchBlt :: proc( - hdcDest: HDC, - xDest: c_int, - yDest: c_int, - wDest: c_int, - hDest: c_int, - hdcSrc: HDC, - xSrc: c_int, - ySrc: c_int, - wSrc: c_int, - hSrc: c_int, - rop: DWORD, - ) -> BOOL --- - - SetPixelFormat :: proc(hdc: HDC, format: c_int, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL --- - ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int --- - DescribePixelFormat :: proc(hdc: HDC, iPixelFormat: c_int, nBytes: UINT, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int --- - SwapBuffers :: proc(HDC) -> BOOL --- + SetPixelFormat :: proc(hdc: HDC, format: INT, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL --- + ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> INT --- + DescribePixelFormat :: proc(hdc: HDC, iPixelFormat: INT, nBytes: UINT, ppfd: ^PIXELFORMATDESCRIPTOR) -> INT --- + SwapBuffers :: proc(hdc: HDC) -> BOOL --- SetDCBrushColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- GetDCBrushColor :: proc(hdc: HDC) -> COLORREF --- - PatBlt :: proc(hdc: HDC, x, y, w, h: c_int, rop: DWORD) -> BOOL --- - Rectangle :: proc(hdc: HDC, left, top, right, bottom: c_int) -> BOOL --- + PatBlt :: proc(hdc: HDC, x, y, w, h: INT, rop: DWORD) -> BOOL --- + Rectangle :: proc(hdc: HDC, left, top, right, bottom: INT) -> BOOL --- - CreateFontW :: proc( - cHeight, cWidth, cEscapement, cOrientation, cWeight: c_int, - bItalic, bUnderline, bStrikeOut, iCharSet, iOutPrecision: DWORD, - iClipPrecision, iQuality, iPitchAndFamily: DWORD, - pszFaceName: LPCWSTR, - ) -> HFONT --- - TextOutW :: proc(hdc: HDC, x, y: c_int, lpString: LPCWSTR, c: c_int) -> BOOL --- - GetTextExtentPoint32W :: proc(hdc: HDC, lpString: LPCWSTR, c: c_int, psizl: LPSIZE) -> BOOL --- + CreateFontW :: proc(cHeight, cWidth, cEscapement, cOrientation, cWeight: INT, bItalic, bUnderline, bStrikeOut, iCharSet, iOutPrecision: DWORD, iClipPrecision, iQuality, iPitchAndFamily: DWORD, pszFaceName: LPCWSTR) -> HFONT --- + CreateFontIndirectW :: proc(lplf: ^LOGFONTW) -> HFONT --- + CreateFontIndirectExW :: proc(unnamedParam1: ^ENUMLOGFONTEXDVW) -> HFONT --- + AddFontResourceW :: proc(unnamedParam1: LPCWSTR) -> INT --- + AddFontResourceExW :: proc(name: LPCWSTR, fl: DWORD, res: PVOID) -> INT --- + AddFontMemResourceEx :: proc(pFileView: PVOID, cjSize: DWORD, pvResrved: PVOID, pNumFonts: ^DWORD) -> HANDLE --- + EnumFontsW :: proc(hdc: HDC, lpLogfont: LPCWSTR, lpProc: FONTENUMPROCW, lParam: LPARAM) -> INT --- + EnumFontFamiliesW :: proc(hdc: HDC, lpLogfont: LPCWSTR, lpProc: FONTENUMPROCW, lParam: LPARAM) -> INT --- + EnumFontFamiliesExW :: proc(hdc: HDC, lpLogfont: LPLOGFONTW, lpProc: FONTENUMPROCW, lParam: LPARAM, dwFlags: DWORD) -> INT --- + + TextOutW :: proc(hdc: HDC, x, y: INT, lpString: LPCWSTR, c: INT) -> BOOL --- + GetTextExtentPoint32W :: proc(hdc: HDC, lpString: LPCWSTR, c: INT, psizl: LPSIZE) -> BOOL --- GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL --- CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH --- - GetObjectW :: proc(h: HANDLE, c: c_int, pv: LPVOID) -> int --- - CreateCompatibleBitmap :: proc(hdc: HDC, cx, cy: c_int) -> HBITMAP --- - BitBlt :: proc(hdc: HDC, x, y, cx, cy: c_int, hdcSrc: HDC, x1, y1: c_int, rop: DWORD) -> BOOL --- - GetDIBits :: proc(hdc: HDC, hbm: HBITMAP, start, cLines: UINT, lpvBits: LPVOID, lpbmi: ^BITMAPINFO, usage: UINT) -> int --- + GetObjectW :: proc(h: HANDLE, c: INT, pv: LPVOID) -> int --- + CreateCompatibleBitmap :: proc(hdc: HDC, cx, cy: INT) -> HBITMAP --- + BitBlt :: proc(hdc: HDC, x, y, cx, cy: INT, hdcSrc: HDC, x1, y1: INT, rop: DWORD) -> BOOL --- + GetDIBits :: proc(hdc: HDC, hbm: HBITMAP, start, cLines: UINT, lpvBits: LPVOID, lpbmi: ^BITMAPINFO, usage: UINT) -> INT --- + SetDIBits :: proc(hdc: HDC, hbm: HBITMAP, start: UINT, cLines: UINT, lpBits: VOID, lpbmi: ^BITMAPINFO, ColorUse: UINT) -> INT --- + SetDIBColorTable :: proc(hdc: HDC, iStart: UINT, cEntries: UINT, prgbq: ^RGBQUAD) -> UINT --- + GetDIBColorTable :: proc(hdc: HDC, iStart: UINT, cEntries: UINT, prgbq: ^RGBQUAD) -> UINT --- + + CreatePen :: proc(iStyle, cWidth: INT, color: COLORREF) -> HPEN --- + ExtCreatePen :: proc(iPenStyle, cWidth: DWORD, plbrush: ^LOGBRUSH, cStyle: DWORD, pstyle: ^DWORD) -> HPEN --- + SetDCPenColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- + GetDCPenColor :: proc(hdc: HDC) -> COLORREF --- + + CreatePalette :: proc(plpal: ^LOGPALETTE) -> HPALETTE --- + SelectPalette :: proc(hdc: HDC, hPal: HPALETTE, bForceBkgd: BOOL) -> HPALETTE --- + RealizePalette :: proc(hdc: HDC) -> UINT --- + + SetTextColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- + RoundRect :: proc(hdc: HDC, left: INT, top: INT, right: INT, bottom: INT, width: INT, height: INT) -> BOOL --- + SetPixel :: proc(hdc: HDC, x: INT, y: INT, color: COLORREF) -> COLORREF --- + + GdiTransparentBlt :: proc(hdcDest: HDC, xoriginDest, yoriginDest, wDest, hDest: INT, hdcSrc: HDC, xoriginSrc, yoriginSrc, wSrc, hSrc: INT, crTransparent: UINT) -> BOOL --- + GdiGradientFill :: proc(hdc: HDC, pVertex: PTRIVERTEX, nVertex: ULONG, pMesh: PVOID, nCount: ULONG, ulMode: ULONG) -> BOOL --- + GdiAlphaBlend :: proc(hdcDest: HDC, xoriginDest, yoriginDest, wDest, hDest: INT, hdcSrc: HDC, xoriginSrc, yoriginSrc, wSrc, hSrc: INT, ftn: BLENDFUNCTION) -> BOOL --- } -RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF { - return transmute(COLORREF)[4]u8{r, g, b, 0} +RGB :: #force_inline proc "contextless" (#any_int r, g, b: int) -> COLORREF { + return COLORREF(DWORD(BYTE(r)) | (DWORD(BYTE(g)) << 8) | (DWORD(BYTE(b)) << 16)) +} + +PALETTERGB :: #force_inline proc "contextless" (#any_int r, g, b: int) -> COLORREF { + return 0x02000000 | RGB(r, g, b) +} + +PALETTEINDEX :: #force_inline proc "contextless" (#any_int i: int) -> COLORREF { + return COLORREF(DWORD(0x01000000) | DWORD(WORD(i))) } FXPT2DOT30 :: distinct fixed.Fixed(i32, 30) CIEXYZ :: struct { - ciexyzX: FXPT2DOT30, - ciexyzY: FXPT2DOT30, - ciexyzZ: FXPT2DOT30, + ciexyzX, ciexyzY, ciexyzZ: FXPT2DOT30, } CIEXYZTRIPLE :: struct { - ciexyzRed: CIEXYZ, - ciexyzGreen: CIEXYZ, - ciexyzBlue: CIEXYZ, + ciexyzRed, ciexyzGreen, ciexyzBlue: CIEXYZ, } // https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapv5header @@ -138,3 +127,227 @@ BITMAPV5HEADER :: struct { bV5ProfileSize: DWORD, bV5Reserved: DWORD, } + +PALETTEENTRY :: struct { + peRed, peGreen, peBlue, peFlags: BYTE, +} + +LOGPALETTE :: struct { + palVersion: WORD, + palNumEntries: WORD, + palPalEntry: []PALETTEENTRY, +} + +BKMODE :: enum { + TRANSPARENT = 1, + OPAQUE = 2, +} + +ICONINFOEXW :: struct { + cbSize: DWORD, + fIcon: BOOL, + xHotspot, yHotspot: DWORD, + hbmMask, hbmColor: HBITMAP, + wResID: WORD, + szModName: [MAX_PATH]WCHAR, + szResName: [MAX_PATH]WCHAR, +} +PICONINFOEXW :: ^ICONINFOEXW + +AC_SRC_OVER :: 0x00 +AC_SRC_ALPHA :: 0x01 + +TransparentBlt :: GdiTransparentBlt +GradientFill :: GdiGradientFill +AlphaBlend :: GdiAlphaBlend + +COLOR16 :: USHORT +TRIVERTEX :: struct { + x, y: LONG, + Red, Green, Blue, Alpha: COLOR16, +} +PTRIVERTEX :: ^TRIVERTEX + +GRADIENT_TRIANGLE :: struct { + Vertex1, Vertex2, Vertex3: ULONG, +} +PGRADIENT_TRIANGLE :: ^GRADIENT_TRIANGLE + +GRADIENT_RECT :: struct { + UpperLeft, LowerRight: ULONG, +} +PGRADIENT_RECT :: ^GRADIENT_RECT + +BLENDFUNCTION :: struct { + BlendOp, BlendFlags, SourceConstantAlpha, AlphaFormat: BYTE, +} + +GRADIENT_FILL_RECT_H : ULONG : 0x00000000 +GRADIENT_FILL_RECT_V : ULONG : 0x00000001 +GRADIENT_FILL_TRIANGLE : ULONG : 0x00000002 +GRADIENT_FILL_OP_FLAG : ULONG : 0x000000ff + +/* Brush Styles */ +BS_SOLID :: 0 +BS_NULL :: 1 +BS_HOLLOW :: BS_NULL +BS_HATCHED :: 2 +BS_PATTERN :: 3 +BS_INDEXED :: 4 +BS_DIBPATTERN :: 5 +BS_DIBPATTERNPT :: 6 +BS_PATTERN8X8 :: 7 +BS_DIBPATTERN8X8 :: 8 +BS_MONOPATTERN :: 9 + +/* Hatch Styles */ +HS_HORIZONTAL :: 0 /* ----- */ +HS_VERTICAL :: 1 /* ||||| */ +HS_FDIAGONAL :: 2 /* \\\\\ */ +HS_BDIAGONAL :: 3 /* ///// */ +HS_CROSS :: 4 /* +++++ */ +HS_DIAGCROSS :: 5 /* xxxxx */ +HS_API_MAX :: 12 + +/* Pen Styles */ +PS_SOLID :: 0 +PS_DASH :: 1 /* ------- */ +PS_DOT :: 2 /* ....... */ +PS_DASHDOT :: 3 /* _._._._ */ +PS_DASHDOTDOT :: 4 /* _.._.._ */ +PS_NULL :: 5 +PS_INSIDEFRAME :: 6 +PS_USERSTYLE :: 7 +PS_ALTERNATE :: 8 +PS_STYLE_MASK :: 0x0000000F +PS_ENDCAP_ROUND :: 0x00000000 +PS_ENDCAP_SQUARE :: 0x00000100 +PS_ENDCAP_FLAT :: 0x00000200 +PS_ENDCAP_MASK :: 0x00000F00 +PS_JOIN_ROUND :: 0x00000000 +PS_JOIN_BEVEL :: 0x00001000 +PS_JOIN_MITER :: 0x00002000 +PS_JOIN_MASK :: 0x0000F000 +PS_COSMETIC :: 0x00000000 +PS_GEOMETRIC :: 0x00010000 +PS_TYPE_MASK :: 0x000F0000 + +LOGBRUSH :: struct { + lbStyle: UINT, + lbColor: COLORREF, + lbHatch: ULONG_PTR, +} +PLOGBRUSH :: ^LOGBRUSH + +/* CombineRgn() Styles */ +RGN_AND :: 1 +RGN_OR :: 2 +RGN_XOR :: 3 +RGN_DIFF :: 4 +RGN_COPY :: 5 + +/* StretchBlt() Modes */ +// BLACKONWHITE :: 1 +// WHITEONBLACK :: 2 +// COLORONCOLOR :: 3 +// HALFTONE :: 4 + +/* PolyFill() Modes */ +ALTERNATE :: 1 +WINDING :: 2 + +/* Layout Orientation Options */ +LAYOUT_RTL :: 0x00000001 // Right to left +LAYOUT_BTT :: 0x00000002 // Bottom to top +LAYOUT_VBH :: 0x00000004 // Vertical before horizontal +LAYOUT_ORIENTATIONMASK :: (LAYOUT_RTL | LAYOUT_BTT | LAYOUT_VBH) + +/* Text Alignment Options */ +TA_NOUPDATECP :: 0 +TA_UPDATECP :: 1 + +TA_LEFT :: 0 +TA_RIGHT :: 2 +TA_CENTER :: 6 + +TA_TOP :: 0 +TA_BOTTOM :: 8 +TA_BASELINE :: 24 +TA_RTLREADING :: 256 +TA_MASK :: (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING) + +MM_MAX_NUMAXES :: 16 +DESIGNVECTOR :: struct { + dvReserved: DWORD, + dvNumAxes: DWORD, + dvValues: [MM_MAX_NUMAXES]LONG, +} + +LF_FACESIZE :: 32 +LF_FULLFACESIZE :: 64 + +LOGFONTW :: struct { + lfHeight: LONG, + lfWidth: LONG, + lfEscapement: LONG, + lfOrientation: LONG, + lfWeight: LONG, + lfItalic: BYTE, + lfUnderline: BYTE, + lfStrikeOut: BYTE, + lfCharSet: BYTE, + lfOutPrecision: BYTE, + lfClipPrecision: BYTE, + lfQuality: BYTE, + lfPitchAndFamily: BYTE, + lfFaceName: [LF_FACESIZE]WCHAR, +} +LPLOGFONTW :: ^LOGFONTW + +ENUMLOGFONTW :: struct { + elfLogFont: LOGFONTW, + elfFullName: [LF_FULLFACESIZE]WCHAR, + elfStyle: [LF_FACESIZE]WCHAR, +} +LPENUMLOGFONTW :: ^ENUMLOGFONTW + +ENUMLOGFONTEXW :: struct { + elfLogFont: LOGFONTW, + elfFullName: [LF_FULLFACESIZE]WCHAR, + elfStyle: [LF_FACESIZE]WCHAR, + elfScript: [LF_FACESIZE]WCHAR, +} + +ENUMLOGFONTEXDVW :: struct { + elfEnumLogfontEx: ENUMLOGFONTEXW, + elfDesignVector: DESIGNVECTOR, +} + +NEWTEXTMETRICW :: struct { + tmHeight: LONG, + tmAscent: LONG, + tmDescent: LONG, + tmInternalLeading: LONG, + tmExternalLeading: LONG, + tmAveCharWidth: LONG, + tmMaxCharWidth: LONG, + tmWeight: LONG, + tmOverhang: LONG, + tmDigitizedAspectX: LONG, + tmDigitizedAspectY: LONG, + tmFirstChar: WCHAR, + tmLastChar: WCHAR, + tmDefaultChar: WCHAR, + tmBreakChar: WCHAR, + tmItalic: BYTE, + tmUnderlined: BYTE, + tmStruckOut: BYTE, + tmPitchAndFamily: BYTE, + tmCharSet: BYTE, + ntmFlags: DWORD, + ntmSizeEM: UINT, + ntmCellHeight: UINT, + ntmAvgWidth: UINT, +} + +FONTENUMPROCW :: #type proc(lpelf: ^ENUMLOGFONTW, lpntm: ^NEWTEXTMETRICW, FontType: DWORD, lParam: LPARAM) -> INT diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 16b6fa244..eb1fec2df 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -46,8 +46,11 @@ foreign kernel32 { dwCursorPosition: COORD) -> BOOL --- SetConsoleTextAttribute :: proc(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL --- - SetConsoleOutputCP :: proc(wCodePageID: UINT) -> BOOL --- - + GetConsoleCP :: proc() -> CODEPAGE --- + SetConsoleCP :: proc(wCodePageID: CODEPAGE) -> BOOL --- + GetConsoleOutputCP :: proc() -> CODEPAGE --- + SetConsoleOutputCP :: proc(wCodePageID: CODEPAGE) -> BOOL --- + GetFileInformationByHandle :: proc(hFile: HANDLE, lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) -> BOOL --- SetHandleInformation :: proc(hObject: HANDLE, dwMask: DWORD, @@ -224,6 +227,7 @@ foreign kernel32 { SetEnvironmentVariableW :: proc(n: LPCWSTR, v: LPCWSTR) -> BOOL --- GetEnvironmentStringsW :: proc() -> LPWCH --- FreeEnvironmentStringsW :: proc(env_ptr: LPWCH) -> BOOL --- + ExpandEnvironmentStringsW :: proc(lpSrc: LPCWSTR, lpDst: LPWSTR, nSize: DWORD) -> DWORD --- GetModuleFileNameW :: proc(hModule: HMODULE, lpFilename: LPWSTR, nSize: DWORD) -> DWORD --- CreateDirectoryW :: proc( lpPathName: LPCWSTR, @@ -408,11 +412,34 @@ foreign kernel32 { GetFileAttributesExW :: proc(lpFileName: LPCWSTR, fInfoLevelId: GET_FILEEX_INFO_LEVELS, lpFileInformation: LPVOID) -> BOOL --- GetSystemInfo :: proc(system_info: ^SYSTEM_INFO) --- GetVersionExW :: proc(osvi: ^OSVERSIONINFOEXW) --- - + GetSystemDirectoryW :: proc(lpBuffer: LPWSTR, uSize: UINT) -> UINT --- + GetWindowsDirectoryW :: proc(lpBuffer: LPWSTR, uSize: UINT) -> UINT --- + GetSystemDefaultLangID :: proc() -> LANGID --- + GetSystemDefaultLCID :: proc() -> LCID --- + GetSystemDefaultLocaleName :: proc(lpLocaleName: LPWSTR, cchLocaleName: INT) -> INT --- + LCIDToLocaleName :: proc(Locale: LCID, lpName: LPWSTR, cchName: INT, dwFlags: DWORD) -> INT --- + LocaleNameToLCID :: proc(lpName: LPCWSTR, dwFlags: DWORD) -> LCID --- + SetDllDirectoryW :: proc(lpPathName: LPCWSTR) -> BOOL --- + AddDllDirectory :: proc(NewDirectory: PCWSTR) -> rawptr --- + RemoveDllDirectory :: proc(Cookie: rawptr) -> BOOL --- LoadLibraryW :: proc(c_str: LPCWSTR) -> HMODULE --- + LoadLibraryExW :: proc(c_str: LPCWSTR, hFile: HANDLE, dwFlags: LOAD_LIBRARY_FLAGS) -> HMODULE --- FreeLibrary :: proc(h: HMODULE) -> BOOL --- GetProcAddress :: proc(h: HMODULE, c_str: LPCSTR) -> rawptr --- + LoadResource :: proc(hModule: HMODULE, hResInfo: HRSRC) -> HGLOBAL --- + FreeResource :: proc(hResData: HGLOBAL) -> BOOL --- + LockResource :: proc(hResData: HGLOBAL) -> LPVOID --- + SizeofResource :: proc(hModule: HMODULE, hResInfo: HRSRC) -> DWORD --- + FindResourceW :: proc(hModule: HMODULE, lpName: LPCWSTR, lpType: LPCWSTR) -> HRSRC --- + FindResourceExW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpName: LPCWSTR, wLanguage: LANGID) -> HRSRC --- + EnumResourceNamesW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpEnumFunc: ENUMRESNAMEPROCW, lParam: LONG_PTR) -> BOOL --- + EnumResourceNamesExW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpEnumFunc: ENUMRESNAMEPROCW, lParam: LONG_PTR, dwFlags: DWORD, LangId: LANGID) -> BOOL --- + EnumResourceTypesExW :: proc(hModule: HMODULE, lpEnumFunc: ENUMRESTYPEPROCW, lParam: LONG_PTR, dwFlags: DWORD, LangId: LANGID) -> BOOL --- + EnumResourceLanguagesExW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpName: LPCWSTR, lpEnumFunc: ENUMRESLANGPROCW, lParam: LONG_PTR, dwFlags: DWORD, LangId: LANGID) -> BOOL --- + LookupIconIdFromDirectory :: proc(presbits: PBYTE, fIcon: BOOL) -> INT --- + LookupIconIdFromDirectoryEx :: proc(presbits: PBYTE, fIcon: BOOL, cxDesired: INT, cyDesired: INT, Flags: UINT) -> INT --- + CreateIconFromResourceEx :: proc(presbits: PBYTE, dwResSize: DWORD, fIcon: BOOL, dwVer: DWORD, cxDesired: INT, cyDesired: INT, Flags: UINT) -> HICON --- GetFullPathNameW :: proc(filename: LPCWSTR, buffer_length: DWORD, buffer: LPCWSTR, file_part: ^LPCWSTR) -> DWORD --- GetLongPathNameW :: proc(short, long: LPCWSTR, len: DWORD) -> DWORD --- @@ -1228,3 +1255,19 @@ GMEM_INVALID_HANDLE :: 0x8000 GHND :: (GMEM_MOVEABLE | GMEM_ZEROINIT) GPTR :: (GMEM_FIXED | GMEM_ZEROINIT) + +LOAD_LIBRARY_FLAGS :: enum DWORD { + DONT_RESOLVE_DLL_REFERENCES = 0x00000001, + LOAD_LIBRARY_AS_DATAFILE = 0x00000002, + // reserved for internal LOAD_PACKAGED_LIBRARY = 0x00000004, + LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008, + LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010, + LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020, + LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040, + LOAD_LIBRARY_REQUIRE_SIGNED_TARGET = 0x00000080, + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100, + LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200, + LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400, + LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800, + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000, +} diff --git a/core/sys/windows/ole32.odin b/core/sys/windows/ole32.odin index d344db5f0..78b4b7226 100644 --- a/core/sys/windows/ole32.odin +++ b/core/sys/windows/ole32.odin @@ -38,7 +38,8 @@ LPUNKNOWN :: ^IUnknown @(default_calling_convention="system") foreign Ole32 { - CoInitializeEx :: proc(reserved: rawptr, co_init: COINIT) -> HRESULT --- + CoInitialize :: proc(reserved: rawptr = nil) -> HRESULT --- + CoInitializeEx :: proc(reserved: rawptr = nil, co_init: COINIT = .APARTMENTTHREADED) -> HRESULT --- CoUninitialize :: proc() --- CoCreateInstance :: proc( @@ -50,4 +51,17 @@ foreign Ole32 { ) -> HRESULT --- CoTaskMemFree :: proc(pv: rawptr) --- + + CLSIDFromProgID :: proc(lpszProgID: LPCOLESTR, lpclsid: LPCLSID) -> HRESULT --- + CLSIDFromProgIDEx :: proc(lpszProgID, LPCOLESTR, lpclsid: LPCLSID) -> HRESULT --- + CLSIDFromString :: proc(lpsz: LPOLESTR, pclsid: LPCLSID) -> HRESULT --- + IIDFromString :: proc(lpsz: LPOLESTR, lpiid: LPIID) -> HRESULT --- + ProgIDFromCLSID :: proc(clsid: REFCLSID, lplpszProgID: ^LPOLESTR) -> HRESULT --- + StringFromCLSID :: proc(rclsid: REFCLSID, lplpsz: ^LPOLESTR) -> HRESULT --- + StringFromGUID2 :: proc(rclsid: REFCLSID, lplpsz: LPOLESTR, cchMax: INT) -> INT --- + StringFromIID :: proc(rclsid: REFIID, lplpsz: ^LPOLESTR) -> HRESULT --- + + PropVariantClear :: proc(pvar: ^PROPVARIANT) -> HRESULT --- + PropVariantCopy :: proc(pvarDest: ^PROPVARIANT, pvarSrc: ^PROPVARIANT) -> HRESULT --- + FreePropVariantArray :: proc(cVariants: ULONG, rgvars: ^PROPVARIANT) -> HRESULT --- } diff --git a/core/sys/windows/shcore.odin b/core/sys/windows/shcore.odin new file mode 100644 index 000000000..54f67989e --- /dev/null +++ b/core/sys/windows/shcore.odin @@ -0,0 +1,25 @@ +// +build windows + +package sys_windows + +foreign import shcore "system:Shcore.lib" + +@(default_calling_convention="system") +foreign shcore { + GetProcessDpiAwareness :: proc(hprocess: HANDLE, value: ^PROCESS_DPI_AWARENESS) -> HRESULT --- + SetProcessDpiAwareness :: proc(value: PROCESS_DPI_AWARENESS) -> HRESULT --- + GetDpiForMonitor :: proc(hmonitor: HMONITOR, dpiType: MONITOR_DPI_TYPE, dpiX: ^UINT, dpiY: ^UINT) -> HRESULT --- +} + +PROCESS_DPI_AWARENESS :: enum DWORD { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2, +} + +MONITOR_DPI_TYPE :: enum DWORD { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT, +} diff --git a/core/sys/windows/shell32.odin b/core/sys/windows/shell32.odin index 4108d54d8..214a0f501 100644 --- a/core/sys/windows/shell32.odin +++ b/core/sys/windows/shell32.odin @@ -30,6 +30,8 @@ foreign shell32 { SHGetKnownFolderIDList :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppidl: rawptr) -> HRESULT --- SHSetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, pszPath: PCWSTR ) -> HRESULT --- SHGetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppszPath: ^LPWSTR) -> HRESULT --- + + ExtractIconExW :: proc(pszFile: LPCWSTR, nIconIndex: INT, phiconLarge: ^HICON, phiconSmall: ^HICON, nIcons: UINT) -> UINT --- } APPBARDATA :: struct { diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 11d2774d6..35fc68abf 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -30,14 +30,19 @@ HICON :: distinct HANDLE HCURSOR :: distinct HANDLE HMENU :: distinct HANDLE HBRUSH :: distinct HANDLE +HPEN :: distinct HANDLE HGDIOBJ :: distinct HANDLE HBITMAP :: distinct HANDLE +HPALETTE :: distinct HANDLE HGLOBAL :: distinct HANDLE HHOOK :: distinct HANDLE HKEY :: distinct HANDLE HDESK :: distinct HANDLE HFONT :: distinct HANDLE HRGN :: distinct HANDLE +HRSRC :: distinct HANDLE +HWINSTA :: distinct HANDLE +HACCEL :: distinct HANDLE BOOL :: distinct b32 BYTE :: distinct u8 BOOLEAN :: distinct b8 @@ -137,11 +142,14 @@ LPSTR :: ^CHAR LPWSTR :: ^WCHAR OLECHAR :: WCHAR LPOLESTR :: ^OLECHAR +LPCOLESTR :: LPCSTR LPFILETIME :: ^FILETIME LPWSABUF :: ^WSABUF LPWSAOVERLAPPED :: distinct rawptr LPWSAOVERLAPPED_COMPLETION_ROUTINE :: distinct rawptr LPCVOID :: rawptr +SCODE :: LONG +PSCODE :: ^SCODE PACCESS_TOKEN :: PVOID PSECURITY_DESCRIPTOR :: PVOID @@ -697,6 +705,92 @@ FW_BLACK :: FW_HEAVY PTIMERAPCROUTINE :: #type proc "system" (lpArgToCompletionRoutine: LPVOID, dwTimerLowValue, dwTimerHighValue: DWORD) +// Character Sets +ANSI_CHARSET :: 0 +DEFAULT_CHARSET :: 1 +SYMBOL_CHARSET :: 2 +SHIFTJIS_CHARSET :: 128 +HANGEUL_CHARSET :: 129 +HANGUL_CHARSET :: 129 +GB2312_CHARSET :: 134 +CHINESEBIG5_CHARSET :: 136 +OEM_CHARSET :: 255 +JOHAB_CHARSET :: 130 +HEBREW_CHARSET :: 177 +ARABIC_CHARSET :: 178 +GREEK_CHARSET :: 161 +TURKISH_CHARSET :: 162 +VIETNAMESE_CHARSET :: 163 +THAI_CHARSET :: 222 +EASTEUROPE_CHARSET :: 238 +RUSSIAN_CHARSET :: 204 +MAC_CHARSET :: 77 +BALTIC_CHARSET :: 186 + +// Font Signature Bitmaps +FS_LATIN1 :: 0x00000001 +FS_LATIN2 :: 0x00000002 +FS_CYRILLIC :: 0x00000004 +FS_GREEK :: 0x00000008 +FS_TURKISH :: 0x00000010 +FS_HEBREW :: 0x00000020 +FS_ARABIC :: 0x00000040 +FS_BALTIC :: 0x00000080 +FS_VIETNAMESE :: 0x00000100 +FS_THAI :: 0x00010000 +FS_JISJAPAN :: 0x00020000 +FS_CHINESESIMP :: 0x00040000 +FS_WANSUNG :: 0x00080000 +FS_CHINESETRAD :: 0x00100000 +FS_JOHAB :: 0x00200000 +FS_SYMBOL :: 0x80000000 + +// Output Precisions +OUT_DEFAULT_PRECIS :: 0 +OUT_STRING_PRECIS :: 1 +OUT_CHARACTER_PRECIS :: 2 +OUT_STROKE_PRECIS :: 3 +OUT_TT_PRECIS :: 4 +OUT_DEVICE_PRECIS :: 5 +OUT_RASTER_PRECIS :: 6 +OUT_TT_ONLY_PRECIS :: 7 +OUT_OUTLINE_PRECIS :: 8 +OUT_SCREEN_OUTLINE_PRECIS :: 9 +OUT_PS_ONLY_PRECIS :: 10 + +// Clipping Precisions +CLIP_DEFAULT_PRECIS :: 0 +CLIP_CHARACTER_PRECIS :: 1 +CLIP_STROKE_PRECIS :: 2 +CLIP_MASK :: 0xf +CLIP_LH_ANGLES :: 1 << 4 +CLIP_TT_ALWAYS :: 2 << 4 +CLIP_DFA_DISABLE :: 4 << 4 +CLIP_EMBEDDED :: 8 << 4 + +// Output Qualities +DEFAULT_QUALITY :: 0 +DRAFT_QUALITY :: 1 +PROOF_QUALITY :: 2 +NONANTIALIASED_QUALITY :: 3 +ANTIALIASED_QUALITY :: 4 +CLEARTYPE_QUALITY :: 5 +CLEARTYPE_NATURAL_QUALITY :: 6 + +// Font Pitches +DEFAULT_PITCH :: 0 +FIXED_PITCH :: 1 +VARIABLE_PITCH :: 2 +MONO_FONT :: 8 + +// Font Families +FF_DONTCARE :: 0 << 4 +FF_ROMAN :: 1 << 4 +FF_SWISS :: 2 << 4 +FF_MODERN :: 3 << 4 +FF_SCRIPT :: 4 << 4 +FF_DECORATIVE :: 5 << 4 + TIMERPROC :: #type proc "system" (HWND, UINT, UINT_PTR, DWORD) WNDPROC :: #type proc "system" (HWND, UINT, WPARAM, LPARAM) -> LRESULT @@ -922,6 +1016,16 @@ MF_RIGHTJUSTIFY :: 0x00004000 MF_MOUSESELECT :: 0x00008000 MF_END :: 0x00000080 // Obsolete -- only used by old RES files +// Menu flags for Add/Check/EnableMenuItem() +MFS_GRAYED :: 0x00000003 +MFS_DISABLED :: MFS_GRAYED +MFS_CHECKED :: MF_CHECKED +MFS_HILITE :: MF_HILITE +MFS_ENABLED :: MF_ENABLED +MFS_UNCHECKED :: MF_UNCHECKED +MFS_UNHILITE :: MF_UNHILITE +MFS_DEFAULT :: MF_DEFAULT + // Flags for TrackPopupMenu TPM_LEFTBUTTON :: 0x0000 TPM_RIGHTBUTTON :: 0x0002 @@ -2179,6 +2283,14 @@ CP_SYMBOL :: 42 // SYMBOL translations CP_UTF7 :: 65000 // UTF-7 translation CP_UTF8 :: 65001 // UTF-8 translation +LCID :: DWORD +LANGID :: WORD + +LANG_NEUTRAL :: 0x00 +LANG_INVARIANT :: 0x7f +SUBLANG_NEUTRAL :: 0x00 // language neutral +SUBLANG_DEFAULT :: 0x01 // user default + MB_ERR_INVALID_CHARS :: 8 WC_ERR_INVALID_CHARS :: 128 @@ -2393,8 +2505,10 @@ REFIID :: ^GUID REFGUID :: GUID IID :: GUID +LPIID :: ^IID CLSID :: GUID REFCLSID :: ^CLSID +LPCLSID :: ^CLSID CLSCTX_INPROC_SERVER :: 0x1 CLSCTX_INPROC_HANDLER :: 0x2 @@ -4165,7 +4279,7 @@ DNS_STATUS :: distinct DWORD // zero is success DNS_INFO_NO_RECORDS :: 9501 DNS_QUERY_NO_RECURSION :: 0x00000004 -DNS_RECORD :: struct { +DNS_RECORD :: struct { // aka DNS_RECORDA pNext: ^DNS_RECORD, pName: cstring, wType: WORD, @@ -4208,3 +4322,7 @@ SOCKADDR :: struct { sa_family: ADDRESS_FAMILY, sa_data: [14]CHAR, } + +ENUMRESNAMEPROCW :: #type proc (hModule: HMODULE, lpType: LPCWSTR, lpName: LPWSTR, lParam: LONG_PTR)-> BOOL +ENUMRESTYPEPROCW :: #type proc (hModule: HMODULE, lpType: LPCWSTR, lParam: LONG_PTR)-> BOOL +ENUMRESLANGPROCW :: #type proc (hModule: HMODULE, lpType: LPCWSTR, lpName: LPWSTR, wIDLanguage: LANGID, lParam: LONG_PTR)-> BOOL diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 1fc0116f5..1463b3906 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -6,16 +6,16 @@ foreign import user32 "system:User32.lib" @(default_calling_convention="system") foreign user32 { - GetClassInfoW :: proc(hInstance: HINSTANCE, lpClassNAme: LPCWSTR, lpWndClass: ^WNDCLASSW) -> BOOL --- - GetClassInfoExW :: proc(hInsatnce: HINSTANCE, lpszClass: LPCWSTR, lpwcx: ^WNDCLASSEXW) -> BOOL --- + GetClassInfoW :: proc(hInstance: HINSTANCE, lpClassName: LPCWSTR, lpWndClass: ^WNDCLASSW) -> BOOL --- + GetClassInfoExW :: proc(hInstance: HINSTANCE, lpszClass: LPCWSTR, lpwcx: ^WNDCLASSEXW) -> BOOL --- - GetClassLongW :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- - SetClassLongW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG) -> DWORD --- + GetClassLongW :: proc(hWnd: HWND, nIndex: INT) -> DWORD --- + SetClassLongW :: proc(hWnd: HWND, nIndex: INT, dwNewLong: LONG) -> DWORD --- - GetWindowLongW :: proc(hWnd: HWND, nIndex: c_int) -> LONG --- - SetWindowLongW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG) -> LONG --- + GetWindowLongW :: proc(hWnd: HWND, nIndex: INT) -> LONG --- + SetWindowLongW :: proc(hWnd: HWND, nIndex: INT, dwNewLong: LONG) -> LONG --- - GetClassNameW :: proc(hWnd: HWND, lpClassName: LPWSTR, nMaxCount: c_int) -> c_int --- + GetClassNameW :: proc(hWnd: HWND, lpClassName: LPWSTR, nMaxCount: INT) -> INT --- RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM --- RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- @@ -26,10 +26,10 @@ foreign user32 { lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, - X: c_int, - Y: c_int, - nWidth: c_int, - nHeight: c_int, + X: INT, + Y: INT, + nWidth: INT, + nHeight: INT, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, @@ -38,24 +38,33 @@ foreign user32 { DestroyWindow :: proc(hWnd: HWND) -> BOOL --- - ShowWindow :: proc(hWnd: HWND, nCmdShow: c_int) -> BOOL --- + ShowWindow :: proc(hWnd: HWND, nCmdShow: INT) -> BOOL --- IsWindow :: proc(hWnd: HWND) -> BOOL --- + IsWindowVisible :: proc(hwnd: HWND) -> BOOL --- + IsWindowEnabled :: proc(hwnd: HWND) -> BOOL --- + IsIconic :: proc(hwnd: HWND) -> BOOL --- BringWindowToTop :: proc(hWnd: HWND) -> BOOL --- GetTopWindow :: proc(hWnd: HWND) -> HWND --- SetForegroundWindow :: proc(hWnd: HWND) -> BOOL --- GetForegroundWindow :: proc() -> HWND --- + GetDesktopWindow :: proc() -> HWND --- UpdateWindow :: proc(hWnd: HWND) -> BOOL --- SetActiveWindow :: proc(hWnd: HWND) -> HWND --- GetActiveWindow :: proc() -> HWND --- RedrawWindow :: proc(hwnd: HWND, lprcUpdate: LPRECT, hrgnUpdate: HRGN, flags: RedrawWindowFlags) -> BOOL --- - + SetParent :: proc(hWndChild: HWND, hWndNewParent: HWND) -> HWND --- + SetPropW :: proc(hWnd: HWND, lpString: LPCWSTR, hData: HANDLE) -> BOOL --- + GetPropW :: proc(hWnd: HWND, lpString: LPCWSTR) -> HANDLE --- + RemovePropW :: proc(hWnd: HWND, lpString: LPCWSTR) -> HANDLE --- + EnumPropsW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW) -> INT --- + EnumPropsExW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW, lParam: LPARAM) -> INT --- GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL --- DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT --- WaitMessage :: proc() -> BOOL --- - MsgWaitForMultipleObjects :: proc(nCount: DWORD, pHandles: ^HANDLE, fWaitAll: bool, dwMilliseconds: DWORD, dwWakeMask: DWORD) -> DWORD --- + MsgWaitForMultipleObjects :: proc(nCount: DWORD, pHandles: ^HANDLE, fWaitAll: BOOL, dwMilliseconds: DWORD, dwWakeMask: DWORD) -> DWORD --- PeekMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- PeekMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- @@ -68,7 +77,7 @@ foreign user32 { PostThreadMessageA :: proc(idThread: DWORD, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- PostThreadMessageW :: proc(idThread: DWORD, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- - PostQuitMessage :: proc(nExitCode: c_int) --- + PostQuitMessage :: proc(nExitCode: INT) --- GetQueueStatus :: proc(flags: UINT) -> DWORD --- @@ -82,33 +91,26 @@ foreign user32 { LoadIconA :: proc(hInstance: HINSTANCE, lpIconName: LPCSTR) -> HICON --- LoadIconW :: proc(hInstance: HINSTANCE, lpIconName: LPCWSTR) -> HICON --- + GetIconInfoExW :: proc(hIcon: HICON, piconinfo: PICONINFOEXW) -> BOOL --- LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR --- LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR --- - LoadImageW :: proc(hInst: HINSTANCE, name: LPCWSTR, type: UINT, cx: c_int, cy: c_int, fuLoad: UINT) -> HANDLE --- + LoadImageW :: proc(hInst: HINSTANCE, name: LPCWSTR, type: UINT, cx, cy: INT, fuLoad: UINT) -> HANDLE --- - CreateIcon :: proc(hInstance: HINSTANCE, nWidth: c_int, nHeight: c_int, cPlanes: BYTE, cBitsPixel: BYTE, lpbANDbits: PBYTE, lpbXORbits: PBYTE) -> HICON --- + CreateIcon :: proc(hInstance: HINSTANCE, nWidth, nHeight: INT, cPlanes: BYTE, cBitsPixel: BYTE, lpbANDbits: PBYTE, lpbXORbits: PBYTE) -> HICON --- CreateIconFromResource :: proc(presbits: PBYTE, dwResSize: DWORD, fIcon: BOOL, dwVer: DWORD) -> HICON --- DestroyIcon :: proc(hIcon: HICON) -> BOOL --- - DrawIcon :: proc(hDC: HDC, X: c_int, Y: c_int, hIcon: HICON) -> BOOL --- + DrawIcon :: proc(hDC: HDC, X, Y: INT, hIcon: HICON) -> BOOL --- - CreateCursor :: proc(hInst: HINSTANCE, xHotSpot: c_int, yHotSpot: c_int, nWidth: c_int, nHeight: c_int, pvANDPlane: PVOID, pvXORPlane: PVOID) -> HCURSOR --- + CreateCursor :: proc(hInst: HINSTANCE, xHotSpot, yHotSpot, nWidth, nHeight: INT, pvANDPlane: PVOID, pvXORPlane: PVOID) -> HCURSOR --- DestroyCursor :: proc(hCursor: HCURSOR) -> BOOL --- GetWindowRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL --- GetClientRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL --- ClientToScreen :: proc(hWnd: HWND, lpPoint: LPPOINT) -> BOOL --- ScreenToClient :: proc(hWnd: HWND, lpPoint: LPPOINT) -> BOOL --- - SetWindowPos :: proc( - hWnd: HWND, - hWndInsertAfter: HWND, - X: c_int, - Y: c_int, - cx: c_int, - cy: c_int, - uFlags: UINT, - ) -> BOOL --- - MoveWindow :: proc(hWnd: HWND, X, Y, hWidth, hHeight: c_int, bRepaint: BOOL) -> BOOL --- - GetSystemMetrics :: proc(nIndex: c_int) -> c_int --- + SetWindowPos :: proc(hWnd: HWND, hWndInsertAfter: HWND, X, Y, cx, cy: INT, uFlags: UINT) -> BOOL --- + MoveWindow :: proc(hWnd: HWND, X, Y, hWidth, hHeight: INT, bRepaint: BOOL) -> BOOL --- + GetSystemMetrics :: proc(nIndex: INT) -> INT --- AdjustWindowRect :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL) -> BOOL --- AdjustWindowRectEx :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD) -> BOOL --- AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL --- @@ -118,18 +120,36 @@ foreign user32 { GetWindowDC :: proc(hWnd: HWND) -> HDC --- GetDC :: proc(hWnd: HWND) -> HDC --- - ReleaseDC :: proc(hWnd: HWND, hDC: HDC) -> c_int --- + GetDCEx :: proc(hWnd: HWND, hrgnClip: HRGN, flags: DWORD) -> HDC --- + ReleaseDC :: proc(hWnd: HWND, hDC: HDC) -> INT --- - GetDlgCtrlID :: proc(hWnd: HWND) -> c_int --- - GetDlgItem :: proc(hDlg: HWND, nIDDlgItem: c_int) -> HWND --- + GetDlgCtrlID :: proc(hWnd: HWND) -> INT --- + GetDlgItem :: proc(hDlg: HWND, nIDDlgItem: INT) -> HWND --- + CreateMenu :: proc() -> HMENU --- CreatePopupMenu :: proc() -> HMENU --- + DeleteMenu :: proc(hMenu: HMENU, uPosition: UINT, uFlags: UINT) -> BOOL --- DestroyMenu :: proc(hMenu: HMENU) -> BOOL --- + InsertMenuW :: proc(hMenu: HMENU, uPosition: UINT, uFlags: UINT, uIDNewItem: UINT_PTR, lpNewItem: LPCWSTR) -> BOOL --- AppendMenuW :: proc(hMenu: HMENU, uFlags: UINT, uIDNewItem: UINT_PTR, lpNewItem: LPCWSTR) -> BOOL --- + GetMenu :: proc(hWnd: HWND) -> HMENU --- SetMenu :: proc(hWnd: HWND, hMenu: HMENU) -> BOOL --- - TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x: int, y: int, nReserved: int, hWnd: HWND, prcRect: ^RECT) -> i32 --- + TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x, y: INT, nReserved: INT, hWnd: HWND, prcRect: ^RECT) -> BOOL --- RegisterWindowMessageW :: proc(lpString: LPCWSTR) -> UINT --- + CreateAcceleratorTableW :: proc(paccel: LPACCEL, cAccel: INT) -> HACCEL --- + DestroyAcceleratorTable :: proc(hAccel: HACCEL) -> BOOL --- + LoadAcceleratorsW :: proc(hInstance: HINSTANCE, lpTableName: LPCWSTR) -> HACCEL --- + TranslateAcceleratorW :: proc(hWnd: HWND, hAccTable: HACCEL, lpMsg: LPMSG) -> INT --- + CopyAcceleratorTableW :: proc(hAccelSrc: HACCEL, lpAccelDst: LPACCEL, cAccelEntries: INT) -> INT --- + + InsertMenuItemW :: proc(hmenu: HMENU, item: UINT, fByPosition: BOOL, lpmi: LPMENUITEMINFOW) -> BOOL --- + GetMenuItemInfoW :: proc(hmenu: HMENU, item: UINT, fByPosition: BOOL, lpmii: LPMENUITEMINFOW) -> BOOL --- + SetMenuItemInfoW :: proc(hmenu: HMENU, item: UINT, fByPositon: BOOL, lpmii: LPMENUITEMINFOW) -> BOOL --- + GetMenuDefaultItem :: proc(hMenu: HMENU, fByPos: UINT, gmdiFlags: UINT) -> UINT --- + SetMenuDefaultItem :: proc(hMenu: HMENU, uItem: UINT, fByPos: UINT) -> BOOL --- + GetMenuItemRect :: proc(hWnd: HWND, hMenu: HMENU, uItem: UINT, lprcItem: LPRECT) -> c_int --- + GetUpdateRect :: proc(hWnd: HWND, lpRect: LPRECT, bErase: BOOL) -> BOOL --- ValidateRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL --- InvalidateRect :: proc(hWnd: HWND, lpRect: ^RECT, bErase: BOOL) -> BOOL --- @@ -142,34 +162,35 @@ foreign user32 { ReleaseCapture :: proc() -> BOOL --- TrackMouseEvent :: proc(lpEventTrack: LPTRACKMOUSEEVENT) -> BOOL --- - GetKeyState :: proc(nVirtKey: c_int) -> SHORT --- - GetAsyncKeyState :: proc(vKey: c_int) -> SHORT --- + GetKeyState :: proc(nVirtKey: INT) -> SHORT --- + GetAsyncKeyState :: proc(vKey: INT) -> SHORT --- GetKeyboardState :: proc(lpKeyState: PBYTE) -> BOOL --- MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT --- - ToUnicode :: proc(nVirtKey: UINT, wScanCode: UINT, lpKeyState: ^BYTE, pwszBuff: LPWSTR, cchBuff: c_int, wFlags: UINT) -> c_int --- + ToUnicode :: proc(nVirtKey: UINT, wScanCode: UINT, lpKeyState: ^BYTE, pwszBuff: LPWSTR, cchBuff: INT, wFlags: UINT) -> INT --- - SetWindowsHookExW :: proc(idHook: c_int, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK --- + SetWindowsHookExW :: proc(idHook: INT, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK --- UnhookWindowsHookEx :: proc(hhk: HHOOK) -> BOOL --- - CallNextHookEx :: proc(hhk: HHOOK, nCode: c_int, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + CallNextHookEx :: proc(hhk: HHOOK, nCode: INT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- SetTimer :: proc(hWnd: HWND, nIDEvent: UINT_PTR, uElapse: UINT, lpTimerFunc: TIMERPROC) -> UINT_PTR --- KillTimer :: proc(hWnd: HWND, uIDEvent: UINT_PTR) -> BOOL --- - // MessageBoxA :: proc(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT) -> c_int --- - MessageBoxW :: proc(hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT) -> c_int --- - // MessageBoxExA :: proc(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT, wLanguageId: WORD) -> c_int --- - MessageBoxExW :: proc(hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT, wLanguageId: WORD) -> c_int --- + // MessageBoxA :: proc(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT) -> INT --- + MessageBoxW :: proc(hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT) -> INT --- + // MessageBoxExA :: proc(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT, wLanguageId: WORD) -> INT --- + MessageBoxExW :: proc(hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT, wLanguageId: WORD) -> INT --- ClipCursor :: proc(lpRect: LPRECT) -> BOOL --- GetCursorPos :: proc(lpPoint: LPPOINT) -> BOOL --- - SetCursorPos :: proc(X: c_int, Y: c_int) -> BOOL --- + SetCursorPos :: proc(X, Y: INT) -> BOOL --- SetCursor :: proc(hCursor: HCURSOR) -> HCURSOR --- when !intrinsics.is_package_imported("raylib") { ShowCursor :: proc(bShow: BOOL) -> INT --- } + EnumDisplayDevicesW :: proc (lpDevice: LPCWSTR, iDevNum: DWORD, lpDisplayDevice: PDISPLAY_DEVICEW, dwFlags: DWORD) -> BOOL --- EnumDisplaySettingsW :: proc(lpszDeviceName: LPCWSTR, iModeNum: DWORD, lpDevMode: ^DEVMODEW) -> BOOL --- MonitorFromPoint :: proc(pt: POINT, dwFlags: Monitor_From_Flags) -> HMONITOR --- @@ -179,6 +200,9 @@ foreign user32 { EnumWindows :: proc(lpEnumFunc: Window_Enum_Proc, lParam: LPARAM) -> BOOL --- + IsProcessDPIAware :: proc() -> BOOL --- + SetProcessDPIAware :: proc() -> BOOL --- + SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT --- GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT --- GetWindowDpiAwarenessContext :: proc(hwnd: HWND) -> DPI_AWARENESS_CONTEXT --- @@ -213,14 +237,14 @@ foreign user32 { lpdwResult: PDWORD_PTR, ) -> LRESULT --- - GetSysColor :: proc(nIndex: c_int) -> DWORD --- - GetSysColorBrush :: proc(nIndex: c_int) -> HBRUSH --- - SetSysColors :: proc(cElements: c_int, lpaElements: ^INT, lpaRgbValues: ^COLORREF) -> BOOL --- + GetSysColor :: proc(nIndex: INT) -> DWORD --- + GetSysColorBrush :: proc(nIndex: INT) -> HBRUSH --- + SetSysColors :: proc(cElements: INT, lpaElements: ^INT, lpaRgbValues: ^COLORREF) -> BOOL --- MessageBeep :: proc(uType: UINT) -> BOOL --- IsDialogMessageW :: proc(hDlg: HWND, lpMsg: LPMSG) -> BOOL --- - GetWindowTextLengthW :: proc(hWnd: HWND) -> c_int --- - GetWindowTextW :: proc(hWnd: HWND, lpString: LPWSTR, nMaxCount: c_int) -> c_int --- + GetWindowTextLengthW :: proc(hWnd: HWND) -> INT --- + GetWindowTextW :: proc(hWnd: HWND, lpString: LPWSTR, nMaxCount: INT) -> INT --- SetWindowTextW :: proc(hWnd: HWND, lpString: LPCWSTR) -> BOOL --- CallWindowProcW :: proc(lpPrevWndFunc: WNDPROC, hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- EnableWindow :: proc(hWnd: HWND, bEnable: BOOL) -> BOOL --- @@ -233,12 +257,20 @@ foreign user32 { GetRegisteredRawInputDevices :: proc(pRawInputDevices: PRAWINPUTDEVICE, puiNumDevices: PUINT, cbSize: UINT) -> UINT --- RegisterRawInputDevices :: proc(pRawInputDevices: PCRAWINPUTDEVICE, uiNumDevices: UINT, cbSize: UINT) -> BOOL --- - SendInput :: proc(cInputs: UINT, pInputs: [^]INPUT, cbSize: c_int) -> UINT --- + SendInput :: proc(cInputs: UINT, pInputs: [^]INPUT, cbSize: INT) -> UINT --- SetLayeredWindowAttributes :: proc(hWnd: HWND, crKey: COLORREF, bAlpha: BYTE, dwFlags: DWORD) -> BOOL --- FillRect :: proc(hDC: HDC, lprc: ^RECT, hbr: HBRUSH) -> int --- - EqualRect :: proc(lprc1: ^RECT, lprc2: ^RECT) -> BOOL --- + EqualRect :: proc(lprc1, lprc2: ^RECT) -> BOOL --- + OffsetRect :: proc(lprc1: ^RECT, dx, dy: INT) -> BOOL --- + InflateRect :: proc(lprc1: ^RECT, dx, dy: INT) -> BOOL --- + IntersectRect :: proc(lprcDst, lprcSrc1, lprcSrc2: ^RECT) -> BOOL --- + SubtractRect :: proc(lprcDst, lprcSrc1, lprcSrc2: ^RECT) -> BOOL --- + UnionRect :: proc(lprcDst, lprcSrc1, lprcSrc2: ^RECT) -> BOOL --- + IsRectEmpty :: proc(lprc: ^RECT) -> BOOL --- + SetRectEmpty :: proc(lprc: ^RECT) -> BOOL --- + CopyRect :: proc(lprcDst, lprcSrc: ^RECT) -> BOOL --- GetWindowInfo :: proc(hwnd: HWND, pwi: PWINDOWINFO) -> BOOL --- GetWindowPlacement :: proc(hWnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL --- @@ -249,19 +281,30 @@ foreign user32 { GetSystemMenu :: proc(hWnd: HWND, bRevert: BOOL) -> HMENU --- EnableMenuItem :: proc(hMenu: HMENU, uIDEnableItem: UINT, uEnable: UINT) -> BOOL --- + MenuItemFromPoint :: proc(hWnd: HWND, hMenu: HMENU, ptScreen: POINT) -> INT --- DrawTextW :: proc(hdc: HDC, lpchText: LPCWSTR, cchText: INT, lprc: LPRECT, format: DrawTextFormat) -> INT --- DrawTextExW :: proc(hdc: HDC, lpchText: LPCWSTR, cchText: INT, lprc: LPRECT, format: DrawTextFormat, lpdtp: PDRAWTEXTPARAMS) -> INT --- + + GetLocaleInfoEx :: proc(lpLocaleName: LPCWSTR, LCType: LCTYPE, lpLCData: LPWSTR, cchData: INT) -> INT --- + IsValidLocaleName :: proc(lpLocaleName: LPCWSTR) -> BOOL --- + ResolveLocaleName :: proc(lpNameToResolve: LPCWSTR, lpLocaleName: LPWSTR, cchLocaleName: INT) -> INT --- + IsValidCodePage :: proc(CodePage: UINT) -> BOOL --- + GetACP :: proc() -> CODEPAGE --- + GetCPInfoExW :: proc(CodePage: CODEPAGE, dwFlags: DWORD, lpCPInfoEx: LPCPINFOEXW) -> BOOL --- + + GetProcessWindowStation :: proc() -> HWINSTA --- + GetUserObjectInformationW :: proc(hObj: HANDLE, nIndex: GetUserObjectInformationFlags, pvInfo: PVOID, nLength: DWORD, lpnLengthNeeded: LPDWORD) -> BOOL --- } CreateWindowW :: #force_inline proc "system" ( lpClassName: LPCTSTR, lpWindowName: LPCTSTR, dwStyle: DWORD, - X: c_int, - Y: c_int, - nWidth: c_int, - nHeight: c_int, + X: INT, + Y: INT, + nWidth: INT, + nHeight: INT, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, @@ -286,11 +329,11 @@ CreateWindowW :: #force_inline proc "system" ( when ODIN_ARCH == .amd64 { @(default_calling_convention="system") foreign user32 { - GetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> ULONG_PTR --- - SetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- + GetClassLongPtrW :: proc(hWnd: HWND, nIndex: INT) -> ULONG_PTR --- + SetClassLongPtrW :: proc(hWnd: HWND, nIndex: INT, dwNewLong: LONG_PTR) -> ULONG_PTR --- - GetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- - SetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- + GetWindowLongPtrW :: proc(hWnd: HWND, nIndex: INT) -> LONG_PTR --- + SetWindowLongPtrW :: proc(hWnd: HWND, nIndex: INT, dwNewLong: LONG_PTR) -> LONG_PTR --- } } else when ODIN_ARCH == .i386 { GetClassLongPtrW :: GetClassLongW @@ -300,8 +343,8 @@ when ODIN_ARCH == .amd64 { SetWindowLongPtrW :: SetWindowLongW } -GET_SC_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> c_int { - return c_int(wParam) & 0xFFF0 +GET_SC_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> INT { + return INT(wParam) & 0xFFF0 } GET_WHEEL_DELTA_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> c_short { @@ -500,8 +543,8 @@ WINDOWPLACEMENT :: struct { flags: UINT, showCmd: UINT, ptMinPosition: POINT, - ptMaxPosition: POINT, - rcNormalPosition: RECT, + ptMaxPosition: POINT, + rcNormalPosition: RECT, } WINDOWINFO :: struct { @@ -519,10 +562,10 @@ WINDOWINFO :: struct { PWINDOWINFO :: ^WINDOWINFO DRAWTEXTPARAMS :: struct { - cbSize: UINT, - iTabLength: int, - iLeftMargin: int, - iRightMargin: int, + cbSize : UINT, + iTabLength: INT, + iLeftMargin: INT, + iRightMargin: INT, uiLengthDrawn: UINT, } PDRAWTEXTPARAMS :: ^DRAWTEXTPARAMS @@ -568,3 +611,95 @@ RedrawWindowFlags :: enum UINT { RDW_FRAME = 0x0400, RDW_NOFRAME = 0x0800, } + +GetUserObjectInformationFlags :: enum INT { + UOI_FLAGS = 1, + UOI_NAME = 2, + UOI_TYPE = 3, + UOI_USER_SID = 4, + UOI_HEAPSIZE = 5, + UOI_IO = 6, + UOI_TIMERPROC_EXCEPTION_SUPPRESSION = 7, +} + +USEROBJECTFLAGS :: struct { + fInherit: BOOL, + fReserved: BOOL, + dwFlags: DWORD, +} + +PROPENUMPROCW :: #type proc(unnamedParam1: HWND, unnamedParam2: LPCWSTR, unnamedParam3: HANDLE) -> BOOL +PROPENUMPROCEXW :: #type proc(unnamedParam1: HWND, unnamedParam2: LPCWSTR, unnamedParam3: HANDLE, unnamedParam4: ULONG_PTR) -> BOOL + +RT_CURSOR :: LPWSTR(uintptr(0x00000001)) +RT_BITMAP :: LPWSTR(uintptr(0x00000002)) +RT_ICON :: LPWSTR(uintptr(0x00000003)) +RT_MENU :: LPWSTR(uintptr(0x00000004)) +RT_DIALOG :: LPWSTR(uintptr(0x00000005)) +RT_STRING :: LPWSTR(uintptr(0x00000006)) +RT_FONTDIR :: LPWSTR(uintptr(0x00000007)) +RT_FONT :: LPWSTR(uintptr(0x00000008)) +RT_ACCELERATOR :: LPWSTR(uintptr(0x00000009)) +RT_RCDATA :: LPWSTR(uintptr(0x0000000A)) +RT_MESSAGETABLE :: LPWSTR(uintptr(0x0000000B)) +RT_GROUP_CURSOR :: LPWSTR(uintptr(0x0000000C)) +RT_GROUP_ICON :: LPWSTR(uintptr(0x0000000E)) +RT_VERSION :: LPWSTR(uintptr(0x00000010)) +RT_DLGINCLUDE :: LPWSTR(uintptr(0x00000011)) +RT_PLUGPLAY :: LPWSTR(uintptr(0x00000013)) +RT_VXD :: LPWSTR(uintptr(0x00000014)) +RT_ANICURSOR :: LPWSTR(uintptr(0x00000015)) +RT_ANIICON :: LPWSTR(uintptr(0x00000016)) +RT_MANIFEST :: LPWSTR(uintptr(0x00000018)) + +CREATEPROCESS_MANIFEST_RESOURCE_ID :: LPWSTR(uintptr(0x00000001)) +ISOLATIONAWARE_MANIFEST_RESOURCE_ID :: LPWSTR(uintptr(0x00000002)) +ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID :: LPWSTR(uintptr(0x00000003)) +ISOLATIONPOLICY_MANIFEST_RESOURCE_ID :: LPWSTR(uintptr(0x00000004)) +ISOLATIONPOLICY_BROWSER_MANIFEST_RESOURCE_ID :: LPWSTR(uintptr(0x00000005)) +MINIMUM_RESERVED_MANIFEST_RESOURCE_ID :: LPWSTR(uintptr(0x00000001)) +MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID :: LPWSTR(uintptr(0x00000010)) + +ACCEL :: struct { + /* Also called the flags field */ + fVirt: BYTE, + key: WORD, + cmd: WORD, +} +LPACCEL :: ^ACCEL + +MIIM_STATE :: 0x00000001 +MIIM_ID :: 0x00000002 +MIIM_SUBMENU :: 0x00000004 +MIIM_CHECKMARKS :: 0x00000008 +MIIM_TYPE :: 0x00000010 +MIIM_DATA :: 0x00000020 + +MIIM_STRING :: 0x00000040 +MIIM_BITMAP :: 0x00000080 +MIIM_FTYPE :: 0x00000100 + +MENUITEMINFOW :: struct { + cbSize: UINT, + fMask: UINT, + fType: UINT, // used if MIIM_TYPE (4.0) or MIIM_FTYPE (>4.0) + fState: UINT, // used if MIIM_STATE + wID: UINT, // used if MIIM_ID + hSubMenu: HMENU, // used if MIIM_SUBMENU + hbmpChecked: HBITMAP, // used if MIIM_CHECKMARKS + hbmpUnchecked: HBITMAP, // used if MIIM_CHECKMARKS + dwItemData: ULONG_PTR, // used if MIIM_DATA + dwTypeData: LPWSTR, // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0) + cch: UINT, // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0) + hbmpItem: HBITMAP, // used if MIIM_BITMAP +} +LPMENUITEMINFOW :: ^MENUITEMINFOW +DISPLAY_DEVICEW :: struct { + cb: DWORD, + DeviceName: [32]WCHAR, + DeviceString: [128]WCHAR, + StateFlags: DWORD, + DeviceID: [128]WCHAR, + DeviceKey: [128]WCHAR, +} +PDISPLAY_DEVICEW :: ^DISPLAY_DEVICEW diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin index c68d58de0..3b76de1da 100644 --- a/core/sys/windows/util.odin +++ b/core/sys/windows/util.odin @@ -6,22 +6,79 @@ import "base:intrinsics" L :: intrinsics.constant_utf16_cstring -LOWORD :: #force_inline proc "contextless" (x: DWORD) -> WORD { +// https://learn.microsoft.com/en-us/windows/win32/winmsg/makeword +MAKEWORD :: #force_inline proc "contextless" (#any_int a, b: int) -> WORD { + return WORD(BYTE(DWORD_PTR(a) & 0xff)) | (WORD(BYTE(DWORD_PTR(b) & 0xff)) << 8) +} + +// https://learn.microsoft.com/en-us/windows/win32/winmsg/makelong +MAKELONG :: #force_inline proc "contextless" (#any_int a, b: int) -> LONG { + return LONG(WORD(DWORD_PTR(a) & 0xffff)) | (LONG(WORD(DWORD_PTR(b) & 0xffff)) << 16) +} + +// https://learn.microsoft.com/en-us/windows/win32/winmsg/loword +LOWORD :: #force_inline proc "contextless" (#any_int x: int) -> WORD { return WORD(x & 0xffff) } -HIWORD :: #force_inline proc "contextless" (x: DWORD) -> WORD { +// https://learn.microsoft.com/en-us/windows/win32/winmsg/hiword +HIWORD :: #force_inline proc "contextless" (#any_int x: int) -> WORD { return WORD(x >> 16) } +// https://learn.microsoft.com/en-us/windows/win32/winmsg/lobyte +LOBYTE :: #force_inline proc "contextless" (w: WORD) -> BYTE { + return BYTE((DWORD_PTR(w)) & 0xff) +} + +// https://learn.microsoft.com/en-us/windows/win32/winmsg/hibyte +HIBYTE :: #force_inline proc "contextless" (w: WORD) -> BYTE { + return BYTE(((DWORD_PTR(w)) >> 8) & 0xff) +} + +// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-makewparam +MAKEWPARAM :: #force_inline proc "contextless" (#any_int l, h: int) -> WPARAM { + return WPARAM(MAKELONG(l, h)) +} + +// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-makelparam +MAKELPARAM :: #force_inline proc "contextless" (#any_int l, h: int) -> LPARAM { + return LPARAM(MAKELONG(l, h)) +} + +// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-makelresult +MAKELRESULT :: #force_inline proc "contextless" (#any_int l, h: int) -> LRESULT { + return LRESULT(MAKELONG(l, h)) +} + +// https://learn.microsoft.com/en-us/windows/win32/api/windowsx/nf-windowsx-get_x_lparam GET_X_LPARAM :: #force_inline proc "contextless" (lp: LPARAM) -> c_int { return cast(c_int)cast(c_short)LOWORD(cast(DWORD)lp) } +// https://learn.microsoft.com/en-us/windows/win32/api/windowsx/nf-windowsx-get_y_lparam GET_Y_LPARAM :: #force_inline proc "contextless" (lp: LPARAM) -> c_int { return cast(c_int)cast(c_short)HIWORD(cast(DWORD)lp) } +// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-makelcid +MAKELCID :: #force_inline proc "contextless" (lgid, srtid: WORD) -> LCID { + return (DWORD(WORD(srtid)) << 16) | DWORD(WORD(lgid)) +} + +// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-makelangid +MAKELANGID :: #force_inline proc "contextless" (p, s: WORD) -> DWORD { + return DWORD(WORD(s)) << 10 | DWORD(WORD(p)) +} + +LANGIDFROMLCID :: #force_inline proc "contextless" (lcid: LCID) -> LANGID { + return LANGID(lcid) +} + +// this one gave me trouble as it do not mask the values. +// the _ in the name is also off comparing to the c code +// i can't find any usage in the odin repo +@(deprecated = "use MAKEWORD") MAKE_WORD :: #force_inline proc "contextless" (x, y: WORD) -> WORD { return x << 8 | y } diff --git a/core/sys/windows/winerror.odin b/core/sys/windows/winerror.odin index 118327ffa..f99a90d4f 100644 --- a/core/sys/windows/winerror.odin +++ b/core/sys/windows/winerror.odin @@ -1,6 +1,189 @@ // +build windows package sys_windows +// https://learn.microsoft.com/en-us/windows/win32/api/winerror/ + +// Values are 32 bit values laid out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code + +// Define the facility codes +FACILITY :: enum DWORD { + NULL = 0, + RPC = 1, + DISPATCH = 2, + STORAGE = 3, + ITF = 4, + WIN32 = 7, + WINDOWS = 8, + SSPI = 9, + SECURITY = 9, + CONTROL = 10, + CERT = 11, + INTERNET = 12, + MEDIASERVER = 13, + MSMQ = 14, + SETUPAPI = 15, + SCARD = 16, + COMPLUS = 17, + AAF = 18, + URT = 19, + ACS = 20, + DPLAY = 21, + UMI = 22, + SXS = 23, + WINDOWS_CE = 24, + HTTP = 25, + USERMODE_COMMONLOG = 26, + WER = 27, + USERMODE_FILTER_MANAGER = 31, + BACKGROUNDCOPY = 32, + CONFIGURATION = 33, + WIA = 33, + STATE_MANAGEMENT = 34, + METADIRECTORY = 35, + WINDOWSUPDATE = 36, + DIRECTORYSERVICE = 37, + GRAPHICS = 38, + SHELL = 39, + NAP = 39, + TPM_SERVICES = 40, + TPM_SOFTWARE = 41, + UI = 42, + XAML = 43, + ACTION_QUEUE = 44, + PLA = 48, + WINDOWS_SETUP = 48, + FVE = 49, + FWP = 50, + WINRM = 51, + NDIS = 52, + USERMODE_HYPERVISOR = 53, + CMI = 54, + USERMODE_VIRTUALIZATION = 55, + USERMODE_VOLMGR = 56, + BCD = 57, + USERMODE_VHD = 58, + USERMODE_HNS = 59, + SDIAG = 60, + WEBSERVICES = 61, + WINPE = 61, + WPN = 62, + WINDOWS_STORE = 63, + INPUT = 64, + QUIC = 65, + EAP = 66, + IORING = 70, + WINDOWS_DEFENDER = 80, + OPC = 81, + XPS = 82, + MBN = 84, + POWERSHELL = 84, + RAS = 83, + P2P_INT = 98, + P2P = 99, + DAF = 100, + BLUETOOTH_ATT = 101, + AUDIO = 102, + STATEREPOSITORY = 103, + VISUALCPP = 109, + SCRIPT = 112, + PARSE = 113, + BLB = 120, + BLB_CLI = 121, + WSBAPP = 122, + BLBUI = 128, + USN = 129, + USERMODE_VOLSNAP = 130, + TIERING = 131, + WSB_ONLINE = 133, + ONLINE_ID = 134, + DEVICE_UPDATE_AGENT = 135, + DRVSERVICING = 136, + DLS = 153, + DELIVERY_OPTIMIZATION = 208, + USERMODE_SPACES = 231, + USER_MODE_SECURITY_CORE = 232, + USERMODE_LICENSING = 234, + SOS = 160, + OCP_UPDATE_AGENT = 173, + DEBUGGERS = 176, + SPP = 256, + RESTORE = 256, + DMSERVER = 256, + DEPLOYMENT_SERVICES_SERVER = 257, + DEPLOYMENT_SERVICES_IMAGING = 258, + DEPLOYMENT_SERVICES_MANAGEMENT = 259, + DEPLOYMENT_SERVICES_UTIL = 260, + DEPLOYMENT_SERVICES_BINLSVC = 261, + DEPLOYMENT_SERVICES_PXE = 263, + DEPLOYMENT_SERVICES_TFTP = 264, + DEPLOYMENT_SERVICES_TRANSPORT_MANAGEMENT = 272, + DEPLOYMENT_SERVICES_DRIVER_PROVISIONING = 278, + DEPLOYMENT_SERVICES_MULTICAST_SERVER = 289, + DEPLOYMENT_SERVICES_MULTICAST_CLIENT = 290, + DEPLOYMENT_SERVICES_CONTENT_PROVIDER = 293, + HSP_SERVICES = 296, + HSP_SOFTWARE = 297, + LINGUISTIC_SERVICES = 305, + AUDIOSTREAMING = 1094, + TTD = 1490, + ACCELERATOR = 1536, + WMAAECMA = 1996, + DIRECTMUSIC = 2168, + DIRECT3D10 = 2169, + DXGI = 2170, + DXGI_DDI = 2171, + DIRECT3D11 = 2172, + DIRECT3D11_DEBUG = 2173, + DIRECT3D12 = 2174, + DIRECT3D12_DEBUG = 2175, + DXCORE = 2176, + PRESENTATION = 2177, + LEAP = 2184, + AUDCLNT = 2185, + WINCODEC_DWRITE_DWM = 2200, + WINML = 2192, + DIRECT2D = 2201, + DEFRAG = 2304, + USERMODE_SDBUS = 2305, + JSCRIPT = 2306, + PIDGENX = 2561, + EAS = 85, + WEB = 885, + WEB_SOCKET = 886, + MOBILE = 1793, + SQLITE = 1967, + SERVICE_FABRIC = 1968, + UTC = 1989, + WEP = 2049, + SYNCENGINE = 2050, + XBOX = 2339, + GAME = 2340, + PIX = 2748, +} + ERROR_SUCCESS : DWORD : 0 NO_ERROR :: 0 SEC_E_OK : HRESULT : 0x00000000 @@ -42,14 +225,55 @@ ERROR_TIMEOUT : DWORD : 1460 ERROR_DATATYPE_MISMATCH : DWORD : 1629 ERROR_UNSUPPORTED_TYPE : DWORD : 1630 ERROR_NOT_SAME_OBJECT : DWORD : 1656 -ERROR_PIPE_CONNECTED : DWORD : 0x80070217 +ERROR_PIPE_CONNECTED : DWORD : 535 ERROR_PIPE_BUSY : DWORD : 231 -E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001 +// https://learn.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values +S_OK :: 0x00000000 // Operation successful +E_NOTIMPL :: 0x80004001 // Not implemented +E_NOINTERFACE :: 0x80004002 // No such interface supported +E_POINTER :: 0x80004003 // Pointer that is not valid +E_ABORT :: 0x80004004 // Operation aborted +E_FAIL :: 0x80004005 // Unspecified failure +E_UNEXPECTED :: 0x8000FFFF // Unexpected failure +E_ACCESSDENIED :: 0x80070005 // General access denied error +E_HANDLE :: 0x80070006 // Handle that is not valid +E_OUTOFMEMORY :: 0x8007000E // Failed to allocate necessary memory +E_INVALIDARG :: 0x80070057 // One or more arguments are not valid -SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool { return result >= 0 } +// Severity values +SEVERITY :: enum DWORD { + SUCCESS = 0, + ERROR = 1, +} +// Generic test for success on any status value (non-negative numbers indicate success). +SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool { return result >= S_OK } +// and the inverse +FAILED :: #force_inline proc(#any_int result: int) -> bool { return result < S_OK } +// Generic test for error on any status value. +IS_ERROR :: #force_inline proc(#any_int status: int) -> bool { return u32(status) >> 31 == u32(SEVERITY.ERROR) } + +// Return the code +HRESULT_CODE :: #force_inline proc(#any_int hr: int) -> int { return int(u32(hr) & 0xFFFF) } + +// Return the facility +HRESULT_FACILITY :: #force_inline proc(#any_int hr: int) -> FACILITY { return FACILITY((u32(hr) >> 16) & 0x1FFF) } + +// Return the severity +HRESULT_SEVERITY :: #force_inline proc(#any_int hr: int) -> SEVERITY { return SEVERITY((u32(hr) >> 31) & 0x1) } + +// Create an HRESULT value from component pieces +MAKE_HRESULT :: #force_inline proc(#any_int sev: int, #any_int fac: int, #any_int code: int) -> HRESULT { + return HRESULT((uint(sev)<<31) | (uint(fac)<<16) | (uint(code))) +} + +DECODE_HRESULT :: #force_inline proc(#any_int hr: int) -> (SEVERITY, FACILITY, int) { + return HRESULT_SEVERITY(hr), HRESULT_FACILITY(hr), HRESULT_CODE(hr) +} + +// aka ERROR or WIN32_ERROR to hint the WIN32 facility System_Error :: enum DWORD { // The operation completed successfully. SUCCESS = 0x0, diff --git a/core/sys/windows/winmm.odin b/core/sys/windows/winmm.odin index 8ddef29c0..a1786c27a 100644 --- a/core/sys/windows/winmm.odin +++ b/core/sys/windows/winmm.odin @@ -270,7 +270,7 @@ LPHWAVEOUT :: ^HWAVEOUT // https://learn.microsoft.com/en-us/windows/win32/multimedia/multimedia-timer-structures MMTIME :: struct { - wType: UINT, + wType: MMTIME_TYPE, u: struct #raw_union { ms: DWORD, sample: DWORD, @@ -292,6 +292,21 @@ MMTIME :: struct { } LPMMTIME :: ^MMTIME +MMTIME_TYPE :: enum UINT { + /* time in milliseconds */ + TIME_MS = 0x0001, + /* number of wave samples */ + TIME_SAMPLES = 0x0002, + /* current byte offset */ + TIME_BYTES = 0x0004, + /* SMPTE time */ + TIME_SMPTE = 0x0008, + /* MIDI time */ + TIME_MIDI = 0x0010, + /* Ticks within MIDI stream */ + TIME_TICKS = 0x0020, +} + MAXPNAMELEN :: 32 MAXERRORLENGTH :: 256 MMVERSION :: UINT diff --git a/core/sys/windows/winnls.odin b/core/sys/windows/winnls.odin new file mode 100644 index 000000000..292d2fad2 --- /dev/null +++ b/core/sys/windows/winnls.odin @@ -0,0 +1,31 @@ +// +build windows +package sys_windows + +LCTYPE :: distinct DWORD + +LOCALE_NAME_MAX_LENGTH :: 85 +LOCALE_NAME_USER_DEFAULT :: 0 +LOCALE_NAME_INVARIANT : wstring = L("") +LOCALE_NAME_SYSTEM_DEFAULT : wstring = L("!x-sys-default-locale") + +// String Length Maximums. +// 5 ranges, 2 bytes ea., 0 term. +MAX_LEADBYTES :: 12 +// single or double byte +MAX_DEFAULTCHAR :: 2 + +CPINFOEXW :: struct{ + // Maximum length, in bytes, of a character in the code page. + MaxCharSize: UINT, + // The default is usually the "?" character for the code page. + DefaultChar: [MAX_DEFAULTCHAR]BYTE, + // A fixed-length array of lead byte ranges, for which the number of lead byte ranges is variable. + LeadByte: [MAX_LEADBYTES]BYTE, + // The default is usually the "?" character or the katakana middle dot character. + UnicodeDefaultChar: WCHAR, + // Code page value. This value reflects the code page passed to the GetCPInfoEx function. + CodePage: CODEPAGE, + // Full name of the code page. + CodePageName: [MAX_PATH]WCHAR, +} +LPCPINFOEXW :: ^CPINFOEXW diff --git a/core/sys/windows/winver.odin b/core/sys/windows/winver.odin new file mode 100644 index 000000000..091d53d3a --- /dev/null +++ b/core/sys/windows/winver.odin @@ -0,0 +1,92 @@ +// +build windows +package sys_windows + +foreign import version "system:version.lib" + +@(default_calling_convention = "system") +foreign version { + GetFileVersionInfoSizeW :: proc(lpwstrFilename: LPCWSTR, lpdwHandle: LPDWORD) -> DWORD --- + GetFileVersionInfoW :: proc(lptstrFilename: LPCWSTR, dwHandle: DWORD, dwLen: DWORD, lpData: LPVOID) -> BOOL --- + + GetFileVersionInfoSizeExW :: proc(dwFlags: FILE_VER_GET_FLAGS, lpwstrFilename: LPCWSTR, lpdwHandle: LPDWORD) -> DWORD --- + GetFileVersionInfoExW :: proc(dwFlags: FILE_VER_GET_FLAGS, lpwstrFilename: LPCWSTR, dwHandle, dwLen: DWORD, lpData: LPVOID) -> DWORD --- + + VerLanguageNameW :: proc(wLang: DWORD, szLang: LPWSTR, cchLang: DWORD) -> DWORD --- + VerQueryValueW :: proc(pBlock: LPCVOID, lpSubBlock: LPCWSTR, lplpBuffer: ^LPVOID, puLen: PUINT) -> BOOL --- +} + +FILE_VER_GET :: enum DWORD {LOCALISED, NEUTRAL, PREFETCHED} +FILE_VER_GET_FLAGS :: bit_set[FILE_VER_GET; DWORD] + +/* ----- Symbols ----- */ +VS_FILE_INFO :: RT_VERSION +VS_VERSION_INFO :: 1 +VS_USER_DEFINED :: 100 + +VS_FFI_SIGNATURE : DWORD : 0xFEEF04BD + +VS_FFI_STRUCVERSION :: 0x00010000 +VS_FFI_FILEFLAGSMASK :: 0x0000003F + +/* ----- VS_VERSION.dwFileFlags ----- */ +VS_FILEFLAG :: enum DWORD { + DEBUG, + PRERELEASE, + PATCHED, + PRIVATEBUILD, + INFOINFERRED, + SPECIALBUILD, +} +VS_FILEFLAGS :: bit_set[VS_FILEFLAG;DWORD] + +/* ----- VS_VERSION.dwFileOS ----- */ +VOS :: enum WORD { + UNKNOWN = 0x0000, + DOS = 0x0001, + OS216 = 0x0002, + OS232 = 0x0003, + NT = 0x0004, + WINCE = 0x0005, +} +VOS2 :: enum WORD { + BASE = 0x0000, + WINDOWS16 = 0x0001, + PM16 = 0x0002, + PM32 = 0x0003, + WINDOWS32 = 0x0004, +} + +/* ----- VS_VERSION.dwFileType ----- */ +VFT :: enum DWORD { + UNKNOWN = 0x00000000, + APP = 0x00000001, + DLL = 0x00000002, + DRV = 0x00000003, + FONT = 0x00000004, + VXD = 0x00000005, + STATIC_LIB = 0x00000007, +} + +/* ----- VS_VERSION.dwFileSubtype for VFT_WINDOWS_DRV ----- */ +VFT2_WINDOWS_DRV :: enum DWORD { + UNKNOWN = 0x00000000, + DRV_PRINTER = 0x00000001, + DRV_KEYBOARD = 0x00000002, + DRV_LANGUAGE = 0x00000003, + DRV_DISPLAY = 0x00000004, + DRV_MOUSE = 0x00000005, + DRV_NETWORK = 0x00000006, + DRV_SYSTEM = 0x00000007, + DRV_INSTALLABLE = 0x00000008, + DRV_SOUND = 0x00000009, + DRV_COMM = 0x0000000A, + DRV_INPUTMETHOD = 0x0000000B, + DRV_VERSIONED_PRINTER = 0x0000000C, +} + +/* ----- VS_VERSION.dwFileSubtype for VFT_WINDOWS_FONT ----- */ +VFT2_WINDOWS_FONT :: enum DWORD { + FONT_RASTER = 0x00000001, + FONT_VECTOR = 0x00000002, + FONT_TRUETYPE = 0x00000003, +} From 32dcb3caef2b1b060086a9d677e9b9e4fbfe6c84 Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Tue, 11 Jun 2024 18:19:29 +0200 Subject: [PATCH 002/122] windows bindings test --- tests/core/sys/windows/test_kernel32.odin | 22 + tests/core/sys/windows/test_ole32.odin | 67 ++ tests/core/sys/windows/test_windows.odin | 112 +++ .../sys/windows/test_windows_generated.odin | 698 ++++++++++++++++++ tests/core/sys/windows/test_winerror.odin | 34 + 5 files changed, 933 insertions(+) create mode 100644 tests/core/sys/windows/test_kernel32.odin create mode 100644 tests/core/sys/windows/test_ole32.odin create mode 100644 tests/core/sys/windows/test_windows.odin create mode 100644 tests/core/sys/windows/test_windows_generated.odin create mode 100644 tests/core/sys/windows/test_winerror.odin diff --git a/tests/core/sys/windows/test_kernel32.odin b/tests/core/sys/windows/test_kernel32.odin new file mode 100644 index 000000000..7edc38853 --- /dev/null +++ b/tests/core/sys/windows/test_kernel32.odin @@ -0,0 +1,22 @@ +//+build windows +package test_core_sys_windows + +import "base:intrinsics" +import win32 "core:sys/windows" +import "core:testing" + +@(test) +lcid_to_local :: proc(t: ^testing.T) { + lcid: win32.LCID = win32.MAKELANGID(0x09, 0x02) + wname: [512]win32.WCHAR + cc := win32.LCIDToLocaleName(lcid, &wname[0], len(wname) - 1, 0) + testing.expectf(t, cc == 6, "%#x (should be: %#x)", u32(cc), 6) + if cc == 0 {return} + str, err := win32.wstring_to_utf8(win32.wstring(&wname), int(cc)) + testing.expectf(t, err == .None, "%v (should be: %x)", err, 0) + exp :: "en-GB" + testing.expectf(t, str == exp, "%v (should be: %v)", str, exp) + + cc2 := win32.LocaleNameToLCID(L("en-GB"), 0) + testing.expectf(t, cc2 == 0x809, "%#x (should be: %#x)", u32(cc2), 0x809) +} diff --git a/tests/core/sys/windows/test_ole32.odin b/tests/core/sys/windows/test_ole32.odin new file mode 100644 index 000000000..eb01c4489 --- /dev/null +++ b/tests/core/sys/windows/test_ole32.odin @@ -0,0 +1,67 @@ +//+build windows +package test_core_sys_windows + +import "base:intrinsics" +import win32 "core:sys/windows" +import "core:testing" + +@(test) +string_from_clsid :: proc(t: ^testing.T) { + p: win32.LPOLESTR + hr := win32.StringFromCLSID(win32.CLSID_FileOpenDialog, &p) + defer if p != nil {win32.CoTaskMemFree(p)} + + testing.expectf(t, win32.SUCCEEDED(hr), "%x (should be: %x)", u32(hr), 0) + testing.expectf(t, p != nil, "%v is nil", p) + + str, err := win32.wstring_to_utf8(p, 38) + testing.expectf(t, err == .None, "%v (should be: %x)", err, 0) + exp :: "{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}" + testing.expectf(t, str == exp, "%v (should be: %v)", str, exp) +} + +@(test) +clsid_from_string :: proc(t: ^testing.T) { + iid: win32.IID + hr := win32.CLSIDFromString(L("{D20BEEC4-5CA8-4905-AE3B-BF251EA09B53}"), &iid) + testing.expectf(t, win32.SUCCEEDED(hr), "%x (should be: %x)", u32(hr), 0) + exp := win32.FOLDERID_NetworkFolder + testing.expectf(t, iid == exp, "%v (should be: %v)", iid, exp) +} + +@(test) +string_from_iid :: proc(t: ^testing.T) { + p: win32.LPOLESTR + hr := win32.StringFromIID(win32.IID_IFileDialog, &p) + defer if p != nil {win32.CoTaskMemFree(p)} + + testing.expectf(t, win32.SUCCEEDED(hr), "%x (should be: %x)", u32(hr), 0) + testing.expectf(t, p != nil, "%v is nil", p) + + str, err := win32.wstring_to_utf8(p, 40) + testing.expectf(t, err == .None, "%v (should be: %x)", err, 0) + exp :: "{42F85136-DB7E-439C-85F1-E4075D135FC8}" + testing.expectf(t, str == exp, "%v (should be: %v)", str, exp) +} + +@(test) +iid_from_string :: proc(t: ^testing.T) { + iid: win32.IID + hr := win32.IIDFromString(L("{D20BEEC4-5CA8-4905-AE3B-BF251EA09B53}"), &iid) + testing.expectf(t, win32.SUCCEEDED(hr), "%x (should be: %x)", u32(hr), 0) + exp := win32.FOLDERID_NetworkFolder + testing.expectf(t, iid == exp, "%v (should be: %v)", iid, exp) +} + +@(test) +verify_coinit :: proc(t: ^testing.T) { + expect_value(t, win32.COINIT.MULTITHREADED, 0x00000000) + expect_value(t, win32.COINIT.APARTMENTTHREADED, 0x00000002) + expect_value(t, win32.COINIT.DISABLE_OLE1DDE, 0x00000004) + expect_value(t, win32.COINIT.SPEED_OVER_MEMORY, 0x00000008) +} + +// hr := CoInitializeEx(nil, .MULTITHREADED); +// testing.expectf(t, hr == 0, "%x (should be: %v)", u32(hr), 0) +// assert(SUCCEEDED(hr)) +// defer CoUninitialize() diff --git a/tests/core/sys/windows/test_windows.odin b/tests/core/sys/windows/test_windows.odin new file mode 100644 index 000000000..168618144 --- /dev/null +++ b/tests/core/sys/windows/test_windows.odin @@ -0,0 +1,112 @@ +//+build windows +package test_core_sys_windows + +import "core:fmt" +import "base:intrinsics" +import "core:os" +import "base:runtime" +import win32 "core:sys/windows" +import "core:testing" + +L :: intrinsics.constant_utf16_cstring + +TEST_count := 0 +TEST_fail := 0 + +t := &testing.T{} + +when ODIN_TEST { + expect :: testing.expect + expectf :: testing.expectf + log :: testing.log + fmt :: fmt +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + expectf :: proc( + t: ^testing.T, condition: bool, format: string, args: ..any, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf(format, ..args) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +@(private) +expect_size :: proc(t: ^testing.T, $act: typeid, exp: int, loc := #caller_location) { + expectf(t, size_of(act) == exp, "size_of(%v) should be %d was %d", typeid_of(act), exp, size_of(act), loc = loc) +} + +@(private) +expect_value :: proc(t: ^testing.T, #any_int act: u32, #any_int exp: u32, loc := #caller_location) { + expectf(t, act == exp, "0x%8X (should be: 0x%8X)", act, exp, loc = loc) +} + +@(private) +expect_value_64 :: proc(t: ^testing.T, #any_int act: u64, #any_int exp: u64, loc := #caller_location) { + expectf(t, act == exp, "0x%8X (should be: 0x%8X)", act, exp, loc = loc) +} + +@(private) +expect_value_int :: proc(t: ^testing.T, act, exp: int, loc := #caller_location) { + expectf(t, act == exp, "0x%8X (should be: 0x%8X)", act, exp, loc = loc) +} + +@(private) +expect_value_uintptr :: proc(t: ^testing.T, act: uintptr, exp: int, loc := #caller_location) { + expectf(t, act == uintptr(exp), "0x%8X (should be: 0x%8X)", act, uintptr(exp), loc = loc) +} + +@(private) +expect_value_str :: proc(t: ^testing.T, wact, wexp: win32.wstring, loc := #caller_location) { + act, exp: string + err: runtime.Allocator_Error + act, err = win32.wstring_to_utf8(wact, 16) + expectf(t, err == .None, "0x%8X (should be: 0x%8X)", err, 0, loc = loc) + exp, err = win32.wstring_to_utf8(wexp, 16) + expectf(t, err == .None, "0x%8X (should be: 0x%8X)", err, 0, loc = loc) + expectf(t, act == exp, "0x%8X (should be: 0x%8X)", act, exp, loc = loc) +} + +main :: proc() { + verify_win32_type_sizes(t) + verify_macros(t) + verify_winnt(t) + verify_winuser(t) + verify_gdi32(t) + verify_winmm(t) + verify_advapi32(t) + verify_winnls(t) + verify_winreg(t) + verify_verrsrc(t) + verify_error_codes(t) + verify_error_helpers(t) + + lcid_to_local(t) + + string_from_clsid(t) + clsid_from_string(t) + string_from_iid(t) + iid_from_string(t) + verify_coinit(t) + + make_hresult(t) + decode_hresult(t) + + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } +} diff --git a/tests/core/sys/windows/test_windows_generated.odin b/tests/core/sys/windows/test_windows_generated.odin new file mode 100644 index 000000000..5c1c74a96 --- /dev/null +++ b/tests/core/sys/windows/test_windows_generated.odin @@ -0,0 +1,698 @@ +//+build windows +package test_core_sys_windows // generated by win32gen + +import "core:testing" +import win32 "core:sys/windows" + +@(test) +verify_win32_type_sizes :: proc(t: ^testing.T) { + // minwindef.h + expect_size(t, win32.ULONG, 4) + expect_size(t, win32.PULONG, 8) + expect_size(t, win32.USHORT, 2) + expect_size(t, win32.PUSHORT, 8) + expect_size(t, win32.UCHAR, 1) + expect_size(t, win32.DWORD, 4) + expect_size(t, win32.BOOL, 4) + expect_size(t, win32.BYTE, 1) + expect_size(t, win32.WORD, 2) + expect_size(t, win32.PBOOL, 8) + expect_size(t, win32.LPBOOL, 8) + expect_size(t, win32.PBYTE, 8) + expect_size(t, win32.LPBYTE, 8) + expect_size(t, win32.PINT, 8) + expect_size(t, win32.LPINT, 8) + expect_size(t, win32.LPWORD, 8) + expect_size(t, win32.PDWORD, 8) + expect_size(t, win32.LPDWORD, 8) + expect_size(t, win32.LPVOID, 8) + expect_size(t, win32.LPCVOID, 8) + expect_size(t, win32.INT, 4) + expect_size(t, win32.UINT, 4) + expect_size(t, win32.PUINT, 8) + expect_size(t, win32.UINT_PTR, 8) + expect_size(t, win32.LONG_PTR, 8) + expect_size(t, win32.HANDLE, 8) + expect_size(t, win32.WPARAM, 8) + expect_size(t, win32.LPARAM, 8) + expect_size(t, win32.LRESULT, 8) + expect_size(t, win32.LPHANDLE, 8) + expect_size(t, win32.HGLOBAL, 8) + expect_size(t, win32.ATOM, 2) + expect_size(t, win32.HKEY, 8) + expect_size(t, win32.PHKEY, 8) + expect_size(t, win32.HINSTANCE, 8) + expect_size(t, win32.HMODULE, 8) + expect_size(t, win32.HRGN, 8) + expect_size(t, win32.HRSRC, 8) + // windef.h + expect_size(t, win32.HWND, 8) + expect_size(t, win32.HHOOK, 8) + expect_size(t, win32.HGDIOBJ, 8) + expect_size(t, win32.HBITMAP, 8) + expect_size(t, win32.HPALETTE, 8) + expect_size(t, win32.HBRUSH, 8) + expect_size(t, win32.HPEN, 8) + expect_size(t, win32.HFONT, 8) + expect_size(t, win32.HICON, 8) + expect_size(t, win32.HMENU, 8) + expect_size(t, win32.HCURSOR, 8) + expect_size(t, win32.COLORREF, 4) + expect_size(t, win32.RECT, 16) + expect_size(t, win32.POINT, 8) + expect_size(t, win32.SIZE, 8) + // wtypes.h + expect_size(t, win32.DECIMAL, 16) + // fileapi.h + expect_size(t, win32.WIN32_FILE_ATTRIBUTE_DATA, 36) + // libloaderapi.h + expect_size(t, win32.ENUMRESNAMEPROCW, 8) + expect_size(t, win32.ENUMRESTYPEPROCW, 8) + // minwinbase.h + expect_size(t, win32.SYSTEMTIME, 16) + expect_size(t, win32.WIN32_FIND_DATAW, 592) + expect_size(t, win32.CRITICAL_SECTION, 40) + expect_size(t, win32.REASON_CONTEXT, 32) + // guiddef.h + expect_size(t, win32.GUID, 16) + expect_size(t, win32.IID, 16) + expect_size(t, win32.CLSID, 16) + // combaseapi.h + expect_size(t, win32.SCODE, 4) + // commdlg.h + expect_size(t, win32.OPENFILENAMEW, 152) + // wtypesbase.h + expect_size(t, win32.OLECHAR, 2) +} + +@(test) +verify_macros :: proc(t: ^testing.T) { + // minwindef.h + expect_value(t, win32.MAKEWORD(1, 2), 0x00000201) + expect_value(t, win32.MAKEWORD(0x1111, 0x2222), 0x00002211) + expect_value(t, win32.MAKELONG(1, 2), 0x00020001) + expect_value(t, win32.MAKELONG(0x1111, 0x2222), 0x22221111) + expect_value(t, win32.LOWORD(0x12345678), 0x00005678) + expect_value(t, win32.HIWORD(0x12345678), 0x00001234) + expect_value(t, u32(win32.LOBYTE(0x1234)), 0x00000034) + expect_value(t, u32(win32.HIBYTE(0x1234)), 0x00000012) + // winuser.h + expect_value(t, win32.MAKEWPARAM(1, 2), 0x00020001) + expect_value(t, win32.MAKEWPARAM(0x1111, 0x2222), 0x22221111) + expect_value(t, win32.MAKELPARAM(1, 2), 0x00020001) + expect_value(t, win32.MAKELPARAM(0x1111, 0x2222), 0x22221111) + expect_value(t, win32.MAKELRESULT(1, 2), 0x00020001) + expect_value(t, win32.MAKELRESULT(0x1111, 0x2222), 0x22221111) + // winnt.h + expect_value(t, win32.MAKELCID(1, 2), 0x00020001) + expect_value(t, win32.MAKELCID(0x1111, 0x2222), 0x22221111) + expect_value(t, win32.MAKELANGID(1, 2), 0x00000801) + expect_value(t, win32.MAKELANGID(0x1111, 0x2222), 0x00889911) + expect_value(t, win32.LANGIDFROMLCID(0x12345678), 0x00005678) +} + +@(test) +verify_winnt :: proc(t: ^testing.T) { + // winnt.h + expect_size(t, win32.CHAR, 1) + expect_size(t, win32.SHORT, 2) + expect_size(t, win32.LONG, 4) + expect_size(t, win32.INT, 4) + expect_size(t, win32.WCHAR, 2) + expect_size(t, win32.ULONGLONG, 8) + expect_size(t, win32.LARGE_INTEGER, 8) + expect_size(t, win32.PLARGE_INTEGER, 8) + expect_size(t, win32.ULARGE_INTEGER, 8) + expect_size(t, win32.PULARGE_INTEGER, 8) + expect_size(t, win32.BOOLEAN, 1) + expect_size(t, win32.HANDLE, 8) + expect_size(t, win32.PHANDLE, 8) + expect_size(t, win32.HRESULT, 4) + expect_size(t, win32.LCID, 4) + expect_size(t, win32.LANGID, 2) + expect_size(t, win32.LUID, 8) + expect_size(t, win32.SECURITY_INFORMATION, 4) + expect_size(t, win32.ACCESS_MASK, 4) + expect_size(t, win32.REGSAM, 4) + expect_value(t, win32.LANG_NEUTRAL, 0x00000000) + expect_value(t, win32.LANG_INVARIANT, 0x0000007F) + expect_value(t, win32.SUBLANG_NEUTRAL, 0x00000000) + expect_value(t, win32.SUBLANG_DEFAULT, 0x00000001) +} + +@(test) +verify_winuser :: proc(t: ^testing.T) { + // winuser.h + expect_size(t, win32.USEROBJECTFLAGS, 12) + expect_size(t, win32.MSG, 48) + expect_size(t, win32.WINDOWPOS, 40) + expect_size(t, win32.ACCEL, 6) + expect_size(t, win32.MENUITEMINFOW, 80) + expect_size(t, win32.PAINTSTRUCT, 72) + expect_size(t, win32.CREATESTRUCTW, 80) + expect_size(t, win32.WINDOWPLACEMENT, 44) + expect_size(t, win32.MOUSEINPUT, 32) + expect_size(t, win32.KEYBDINPUT, 24) + expect_size(t, win32.HARDWAREINPUT, 8) + expect_size(t, win32.INPUT, 40) + expect_size(t, win32.ICONINFOEXW, 1080) + expect_size(t, win32.RAWINPUTHEADER, 24) + expect_size(t, win32.RAWHID, 12) + expect_size(t, win32.RAWMOUSE, 24) + expect_size(t, win32.RAWKEYBOARD, 16) + expect_size(t, win32.RAWINPUT, 48) + expect_size(t, win32.RAWINPUTDEVICE, 16) + expect_size(t, win32.RAWINPUTDEVICELIST, 16) + expect_size(t, win32.RID_DEVICE_INFO_HID, 16) + expect_size(t, win32.RID_DEVICE_INFO_KEYBOARD, 24) + expect_size(t, win32.RID_DEVICE_INFO_MOUSE, 16) + expect_size(t, win32.RID_DEVICE_INFO, 32) + expect_size(t, win32.WINDOWINFO, 60) + expect_size(t, win32.DRAWTEXTPARAMS, 20) + expect_size(t, win32.BSMINFO, 32) + expect_value(t, win32.BROADCAST_QUERY_DENY, 0x424D5144) + expect_value_64(t, u64(win32.HWND_BROADCAST), 0x0000FFFF) + expect_value_64(t, u64(win32.HWND_MESSAGE), 0xFFFFFFFFFFFFFFFD) + expect_value_64(t, uintptr(win32.MAKEINTRESOURCEW(1)), 0x00000001) + expect_value_64(t, uintptr(win32.MAKEINTRESOURCEW(0x12345678)), 0x00005678) + expect_value_64(t, uintptr(win32.RT_CURSOR), 0x00000001) + expect_value_64(t, uintptr(win32.RT_BITMAP), 0x00000002) + expect_value_64(t, uintptr(win32.RT_ICON), 0x00000003) + expect_value_64(t, uintptr(win32.RT_MENU), 0x00000004) + expect_value_64(t, uintptr(win32.RT_DIALOG), 0x00000005) + expect_value_64(t, uintptr(win32.RT_STRING), 0x00000006) + expect_value_64(t, uintptr(win32.RT_FONTDIR), 0x00000007) + expect_value_64(t, uintptr(win32.RT_FONT), 0x00000008) + expect_value_64(t, uintptr(win32.RT_ACCELERATOR), 0x00000009) + expect_value_64(t, uintptr(win32.RT_RCDATA), 0x0000000A) + expect_value_64(t, uintptr(win32.RT_MESSAGETABLE), 0x0000000B) + expect_value_64(t, uintptr(win32.RT_GROUP_CURSOR), 0x0000000C) + expect_value_64(t, uintptr(win32.RT_GROUP_ICON), 0x0000000E) + expect_value_64(t, uintptr(win32.RT_VERSION), 0x00000010) + expect_value_64(t, uintptr(win32.RT_DLGINCLUDE), 0x00000011) + expect_value_64(t, uintptr(win32.RT_PLUGPLAY), 0x00000013) + expect_value_64(t, uintptr(win32.RT_VXD), 0x00000014) + expect_value_64(t, uintptr(win32.RT_ANICURSOR), 0x00000015) + expect_value_64(t, uintptr(win32.RT_ANIICON), 0x00000016) + expect_value_64(t, uintptr(win32.RT_MANIFEST), 0x00000018) + expect_value_64(t, uintptr(win32.CREATEPROCESS_MANIFEST_RESOURCE_ID), 0x00000001) + expect_value_64(t, uintptr(win32.ISOLATIONAWARE_MANIFEST_RESOURCE_ID), 0x00000002) + expect_value_64(t, uintptr(win32.ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID), 0x00000003) + expect_value_64(t, uintptr(win32.ISOLATIONPOLICY_MANIFEST_RESOURCE_ID), 0x00000004) + expect_value_64(t, uintptr(win32.ISOLATIONPOLICY_BROWSER_MANIFEST_RESOURCE_ID), 0x00000005) + expect_value_64(t, uintptr(win32.MINIMUM_RESERVED_MANIFEST_RESOURCE_ID), 0x00000001) + expect_value_64(t, uintptr(win32.MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID), 0x00000010) + expect_value(t, win32.SM_CXICON, 0x0000000B) + expect_value(t, win32.SM_CYICON, 0x0000000C) + expect_value(t, win32.LR_DEFAULTCOLOR, 0x00000000) + expect_value(t, win32.LR_MONOCHROME, 0x00000001) + expect_value(t, win32.LR_COLOR, 0x00000002) + expect_value(t, win32.LR_COPYRETURNORG, 0x00000004) + expect_value(t, win32.LR_COPYDELETEORG, 0x00000008) + expect_value(t, win32.LR_LOADFROMFILE, 0x00000010) + expect_value(t, win32.LR_LOADTRANSPARENT, 0x00000020) + expect_value(t, win32.LR_DEFAULTSIZE, 0x00000040) + expect_value(t, win32.LR_VGACOLOR, 0x00000080) + expect_value(t, win32.LR_LOADMAP3DCOLORS, 0x00001000) + expect_value(t, win32.LR_CREATEDIBSECTION, 0x00002000) + expect_value(t, win32.LR_COPYFROMRESOURCE, 0x00004000) + expect_value(t, win32.LR_SHARED, 0x00008000) + expect_value(t, win32.NIM_ADD, 0x00000000) + expect_value(t, win32.NIM_MODIFY, 0x00000001) + expect_value(t, win32.NIM_DELETE, 0x00000002) + expect_value(t, win32.NIM_SETFOCUS, 0x00000003) + expect_value(t, win32.NIM_SETVERSION, 0x00000004) + expect_value(t, win32.NIF_MESSAGE, 0x00000001) + expect_value(t, win32.NIF_ICON, 0x00000002) + expect_value(t, win32.NIF_TIP, 0x00000004) + expect_value(t, win32.NIF_STATE, 0x00000008) + expect_value(t, win32.NIF_INFO, 0x00000010) + expect_value(t, win32.NIF_GUID, 0x00000020) + expect_value(t, win32.NIF_REALTIME, 0x00000040) + expect_value(t, win32.NIF_SHOWTIP, 0x00000080) + expect_value(t, win32.MF_INSERT, 0x00000000) + expect_value(t, win32.MF_CHANGE, 0x00000080) + expect_value(t, win32.MF_APPEND, 0x00000100) + expect_value(t, win32.MF_DELETE, 0x00000200) + expect_value(t, win32.MF_REMOVE, 0x00001000) + expect_value(t, win32.MF_BYCOMMAND, 0x00000000) + expect_value(t, win32.MF_BYPOSITION, 0x00000400) + expect_value(t, win32.MF_SEPARATOR, 0x00000800) + expect_value(t, win32.MF_ENABLED, 0x00000000) + expect_value(t, win32.MF_GRAYED, 0x00000001) + expect_value(t, win32.MF_DISABLED, 0x00000002) + expect_value(t, win32.MF_UNCHECKED, 0x00000000) + expect_value(t, win32.MF_CHECKED, 0x00000008) + expect_value(t, win32.MF_USECHECKBITMAPS, 0x00000200) + expect_value(t, win32.MF_STRING, 0x00000000) + expect_value(t, win32.MF_BITMAP, 0x00000004) + expect_value(t, win32.MF_OWNERDRAW, 0x00000100) + expect_value(t, win32.MF_POPUP, 0x00000010) + expect_value(t, win32.MF_MENUBARBREAK, 0x00000020) + expect_value(t, win32.MF_MENUBREAK, 0x00000040) + expect_value(t, win32.MF_UNHILITE, 0x00000000) + expect_value(t, win32.MF_HILITE, 0x00000080) + expect_value(t, win32.MF_DEFAULT, 0x00001000) + expect_value(t, win32.MF_SYSMENU, 0x00002000) + expect_value(t, win32.MF_HELP, 0x00004000) + expect_value(t, win32.MF_RIGHTJUSTIFY, 0x00004000) + expect_value(t, win32.MF_MOUSESELECT, 0x00008000) + expect_value(t, win32.MF_END, 0x00000080) + expect_value(t, win32.MFS_GRAYED, 0x00000003) + expect_value(t, win32.MFS_DISABLED, 0x00000003) + expect_value(t, win32.MFS_CHECKED, 0x00000008) + expect_value(t, win32.MFS_HILITE, 0x00000080) + expect_value(t, win32.MFS_ENABLED, 0x00000000) + expect_value(t, win32.MFS_UNCHECKED, 0x00000000) + expect_value(t, win32.MFS_UNHILITE, 0x00000000) + expect_value(t, win32.MFS_DEFAULT, 0x00001000) + expect_value(t, win32.TPM_LEFTBUTTON, 0x00000000) + expect_value(t, win32.TPM_RIGHTBUTTON, 0x00000002) + expect_value(t, win32.TPM_LEFTALIGN, 0x00000000) + expect_value(t, win32.TPM_CENTERALIGN, 0x00000004) + expect_value(t, win32.TPM_RIGHTALIGN, 0x00000008) + expect_value(t, win32.TPM_TOPALIGN, 0x00000000) + expect_value(t, win32.TPM_VCENTERALIGN, 0x00000010) + expect_value(t, win32.TPM_BOTTOMALIGN, 0x00000020) + expect_value(t, win32.TPM_HORIZONTAL, 0x00000000) + expect_value(t, win32.TPM_VERTICAL, 0x00000040) + expect_value(t, win32.TPM_NONOTIFY, 0x00000080) + expect_value(t, win32.TPM_RETURNCMD, 0x00000100) + expect_value(t, win32.TPM_RECURSE, 0x00000001) + expect_value(t, win32.TPM_HORPOSANIMATION, 0x00000400) + expect_value(t, win32.TPM_HORNEGANIMATION, 0x00000800) + expect_value(t, win32.TPM_VERPOSANIMATION, 0x00001000) + expect_value(t, win32.TPM_VERNEGANIMATION, 0x00002000) + expect_value(t, win32.TPM_NOANIMATION, 0x00004000) + expect_value(t, win32.TPM_LAYOUTRTL, 0x00008000) + expect_value(t, win32.TPM_WORKAREA, 0x00010000) + expect_value(t, win32.MIIM_STATE, 0x00000001) + expect_value(t, win32.MIIM_ID, 0x00000002) + expect_value(t, win32.MIIM_SUBMENU, 0x00000004) + expect_value(t, win32.MIIM_CHECKMARKS, 0x00000008) + expect_value(t, win32.MIIM_TYPE, 0x00000010) + expect_value(t, win32.MIIM_DATA, 0x00000020) + expect_value(t, win32.MIIM_STRING, 0x00000040) + expect_value(t, win32.MIIM_BITMAP, 0x00000080) + expect_value(t, win32.MIIM_FTYPE, 0x00000100) + expect_value(t, win32.ANSI_CHARSET, 0x00000000) + expect_value(t, win32.DEFAULT_CHARSET, 0x00000001) + expect_value(t, win32.SYMBOL_CHARSET, 0x00000002) + expect_value(t, win32.SHIFTJIS_CHARSET, 0x00000080) + expect_value(t, win32.HANGEUL_CHARSET, 0x00000081) + expect_value(t, win32.HANGUL_CHARSET, 0x00000081) + expect_value(t, win32.GB2312_CHARSET, 0x00000086) + expect_value(t, win32.CHINESEBIG5_CHARSET, 0x00000088) + expect_value(t, win32.OEM_CHARSET, 0x000000FF) + expect_value(t, win32.JOHAB_CHARSET, 0x00000082) + expect_value(t, win32.HEBREW_CHARSET, 0x000000B1) + expect_value(t, win32.ARABIC_CHARSET, 0x000000B2) + expect_value(t, win32.GREEK_CHARSET, 0x000000A1) + expect_value(t, win32.TURKISH_CHARSET, 0x000000A2) + expect_value(t, win32.VIETNAMESE_CHARSET, 0x000000A3) + expect_value(t, win32.THAI_CHARSET, 0x000000DE) + expect_value(t, win32.EASTEUROPE_CHARSET, 0x000000EE) + expect_value(t, win32.RUSSIAN_CHARSET, 0x000000CC) + expect_value(t, win32.MAC_CHARSET, 0x0000004D) + expect_value(t, win32.BALTIC_CHARSET, 0x000000BA) + expect_value(t, win32.FS_LATIN1, 0x00000001) + expect_value(t, win32.FS_LATIN2, 0x00000002) + expect_value(t, win32.FS_CYRILLIC, 0x00000004) + expect_value(t, win32.FS_GREEK, 0x00000008) + expect_value(t, win32.FS_TURKISH, 0x00000010) + expect_value(t, win32.FS_HEBREW, 0x00000020) + expect_value(t, win32.FS_ARABIC, 0x00000040) + expect_value(t, win32.FS_BALTIC, 0x00000080) + expect_value(t, win32.FS_VIETNAMESE, 0x00000100) + expect_value(t, win32.FS_THAI, 0x00010000) + expect_value(t, win32.FS_JISJAPAN, 0x00020000) + expect_value(t, win32.FS_CHINESESIMP, 0x00040000) + expect_value(t, win32.FS_WANSUNG, 0x00080000) + expect_value(t, win32.FS_CHINESETRAD, 0x00100000) + expect_value(t, win32.FS_JOHAB, 0x00200000) + expect_value(t, win32.FS_SYMBOL, 0x80000000) + expect_value(t, win32.OUT_DEFAULT_PRECIS, 0x00000000) + expect_value(t, win32.OUT_STRING_PRECIS, 0x00000001) + expect_value(t, win32.OUT_CHARACTER_PRECIS, 0x00000002) + expect_value(t, win32.OUT_STROKE_PRECIS, 0x00000003) + expect_value(t, win32.OUT_TT_PRECIS, 0x00000004) + expect_value(t, win32.OUT_DEVICE_PRECIS, 0x00000005) + expect_value(t, win32.OUT_RASTER_PRECIS, 0x00000006) + expect_value(t, win32.OUT_TT_ONLY_PRECIS, 0x00000007) + expect_value(t, win32.OUT_OUTLINE_PRECIS, 0x00000008) + expect_value(t, win32.OUT_SCREEN_OUTLINE_PRECIS, 0x00000009) + expect_value(t, win32.OUT_PS_ONLY_PRECIS, 0x0000000A) + expect_value(t, win32.CLIP_DEFAULT_PRECIS, 0x00000000) + expect_value(t, win32.CLIP_CHARACTER_PRECIS, 0x00000001) + expect_value(t, win32.CLIP_STROKE_PRECIS, 0x00000002) + expect_value(t, win32.CLIP_MASK, 0x0000000F) + expect_value(t, win32.CLIP_LH_ANGLES, 0x00000010) + expect_value(t, win32.CLIP_TT_ALWAYS, 0x00000020) + expect_value(t, win32.CLIP_DFA_DISABLE, 0x00000040) + expect_value(t, win32.CLIP_EMBEDDED, 0x00000080) + expect_value(t, win32.DEFAULT_QUALITY, 0x00000000) + expect_value(t, win32.DRAFT_QUALITY, 0x00000001) + expect_value(t, win32.PROOF_QUALITY, 0x00000002) + expect_value(t, win32.NONANTIALIASED_QUALITY, 0x00000003) + expect_value(t, win32.ANTIALIASED_QUALITY, 0x00000004) + expect_value(t, win32.CLEARTYPE_QUALITY, 0x00000005) + expect_value(t, win32.CLEARTYPE_NATURAL_QUALITY, 0x00000006) + expect_value(t, win32.DEFAULT_PITCH, 0x00000000) + expect_value(t, win32.FIXED_PITCH, 0x00000001) + expect_value(t, win32.VARIABLE_PITCH, 0x00000002) + expect_value(t, win32.MONO_FONT, 0x00000008) + expect_value(t, win32.FF_DONTCARE, 0x00000000) + expect_value(t, win32.FF_ROMAN, 0x00000010) + expect_value(t, win32.FF_SWISS, 0x00000020) + expect_value(t, win32.FF_MODERN, 0x00000030) + expect_value(t, win32.FF_SCRIPT, 0x00000040) + expect_value(t, win32.FF_DECORATIVE, 0x00000050) +} + +@(test) +verify_gdi32 :: proc(t: ^testing.T) { + // wingdi.h + expect_size(t, win32.DEVMODEW, 220) + expect_size(t, win32.RGBQUAD, 4) + expect_size(t, win32.PIXELFORMATDESCRIPTOR, 40) + expect_size(t, win32.BITMAPINFOHEADER, 40) + expect_size(t, win32.BITMAP, 32) + expect_size(t, win32.BITMAPV5HEADER, 124) + expect_size(t, win32.CIEXYZTRIPLE, 36) + expect_size(t, win32.CIEXYZ, 12) + expect_size(t, win32.FXPT2DOT30, 4) + expect_size(t, win32.TEXTMETRICW, 60) + expect_size(t, win32.POINTFLOAT, 8) + expect_size(t, win32.GLYPHMETRICSFLOAT, 24) + expect_size(t, win32.PALETTEENTRY, 4) + expect_size(t, win32.DESIGNVECTOR, 72) + expect_value(t, win32.LF_FACESIZE, 0x00000020) + expect_value(t, win32.LF_FULLFACESIZE, 0x00000040) + expect_size(t, win32.LOGFONTW, 92) + expect_size(t, win32.ENUMLOGFONTW, 284) + expect_size(t, win32.ENUMLOGFONTEXW, 348) + expect_size(t, win32.ENUMLOGFONTEXDVW, 420) + expect_size(t, win32.NEWTEXTMETRICW, 76) + expect_size(t, win32.LAYERPLANEDESCRIPTOR, 32) + expect_size(t, win32.COLOR16, 2) + expect_size(t, win32.TRIVERTEX, 16) + expect_size(t, win32.GRADIENT_TRIANGLE, 12) + expect_size(t, win32.GRADIENT_RECT, 8) + expect_size(t, win32.BLENDFUNCTION, 4) + expect_size(t, win32.DISPLAY_DEVICEW, 840) + expect_value(t, win32.AC_SRC_OVER, 0x00000000) + expect_value(t, win32.AC_SRC_ALPHA, 0x00000001) + expect_value(t, win32.RGB(12, 34, 56), 0x0038220C) + expect_value(t, win32.PALETTERGB(12, 34, 56), 0x0238220C) + expect_value(t, win32.PALETTEINDEX(123), 0x0100007B) + expect_value(t, win32.GRADIENT_FILL_RECT_H, 0x00000000) + expect_value(t, win32.GRADIENT_FILL_RECT_V, 0x00000001) + expect_value(t, win32.GRADIENT_FILL_TRIANGLE, 0x00000002) + expect_value(t, win32.BS_SOLID, 0x00000000) + expect_value(t, win32.BS_NULL, 0x00000001) + expect_value(t, win32.BS_HOLLOW, 0x00000001) + expect_value(t, win32.BS_HATCHED, 0x00000002) + expect_value(t, win32.BS_PATTERN, 0x00000003) + expect_value(t, win32.BS_INDEXED, 0x00000004) + expect_value(t, win32.BS_DIBPATTERN, 0x00000005) + expect_value(t, win32.BS_DIBPATTERNPT, 0x00000006) + expect_value(t, win32.BS_PATTERN8X8, 0x00000007) + expect_value(t, win32.BS_DIBPATTERN8X8, 0x00000008) + expect_value(t, win32.BS_MONOPATTERN, 0x00000009) + expect_value(t, win32.HS_HORIZONTAL, 0x00000000) + expect_value(t, win32.HS_VERTICAL, 0x00000001) + expect_value(t, win32.HS_FDIAGONAL, 0x00000002) + expect_value(t, win32.HS_BDIAGONAL, 0x00000003) + expect_value(t, win32.HS_CROSS, 0x00000004) + expect_value(t, win32.HS_DIAGCROSS, 0x00000005) + expect_value(t, win32.HS_API_MAX, 0x0000000C) + expect_value(t, win32.PS_SOLID, 0x00000000) + expect_value(t, win32.PS_DASH, 0x00000001) + expect_value(t, win32.PS_DOT, 0x00000002) + expect_value(t, win32.PS_DASHDOT, 0x00000003) + expect_value(t, win32.PS_DASHDOTDOT, 0x00000004) + expect_value(t, win32.PS_NULL, 0x00000005) + expect_value(t, win32.PS_INSIDEFRAME, 0x00000006) + expect_value(t, win32.PS_USERSTYLE, 0x00000007) + expect_value(t, win32.PS_ALTERNATE, 0x00000008) + expect_value(t, win32.PS_STYLE_MASK, 0x0000000F) + expect_value(t, win32.PS_ENDCAP_ROUND, 0x00000000) + expect_value(t, win32.PS_ENDCAP_SQUARE, 0x00000100) + expect_value(t, win32.PS_ENDCAP_FLAT, 0x00000200) + expect_value(t, win32.PS_ENDCAP_MASK, 0x00000F00) + expect_value(t, win32.PS_JOIN_ROUND, 0x00000000) + expect_value(t, win32.PS_JOIN_BEVEL, 0x00001000) + expect_value(t, win32.PS_JOIN_MITER, 0x00002000) + expect_value(t, win32.PS_COSMETIC, 0x00000000) + expect_value(t, win32.PS_GEOMETRIC, 0x00010000) + expect_value(t, win32.PS_TYPE_MASK, 0x000F0000) + // Binary raster ops + expect_value(t, win32.R2_BLACK, 0x00000001) + expect_value(t, win32.R2_NOTMERGEPEN, 0x00000002) + expect_value(t, win32.R2_MASKNOTPEN, 0x00000003) + expect_value(t, win32.R2_NOTCOPYPEN, 0x00000004) + expect_value(t, win32.R2_MASKPENNOT, 0x00000005) + expect_value(t, win32.R2_NOT, 0x00000006) + expect_value(t, win32.R2_XORPEN, 0x00000007) + expect_value(t, win32.R2_NOTMASKPEN, 0x00000008) + expect_value(t, win32.R2_MASKPEN, 0x00000009) + expect_value(t, win32.R2_NOTXORPEN, 0x0000000A) + expect_value(t, win32.R2_NOP, 0x0000000B) + expect_value(t, win32.R2_MERGENOTPEN, 0x0000000C) + expect_value(t, win32.R2_COPYPEN, 0x0000000D) + expect_value(t, win32.R2_MERGEPENNOT, 0x0000000E) + expect_value(t, win32.R2_MERGEPEN, 0x0000000F) + expect_value(t, win32.R2_WHITE, 0x00000010) + // Ternary raster operations + expect_value(t, win32.SRCCOPY, 0x00CC0020) + expect_value(t, win32.SRCPAINT, 0x00EE0086) + expect_value(t, win32.SRCAND, 0x008800C6) + expect_value(t, win32.SRCINVERT, 0x00660046) + expect_value(t, win32.SRCERASE, 0x00440328) + expect_value(t, win32.NOTSRCCOPY, 0x00330008) + expect_value(t, win32.NOTSRCERASE, 0x001100A6) + expect_value(t, win32.MERGECOPY, 0x00C000CA) + expect_value(t, win32.MERGEPAINT, 0x00BB0226) + expect_value(t, win32.PATCOPY, 0x00F00021) + expect_value(t, win32.PATPAINT, 0x00FB0A09) + expect_value(t, win32.PATINVERT, 0x005A0049) + expect_value(t, win32.DSTINVERT, 0x00550009) + expect_value(t, win32.BLACKNESS, 0x00000042) + expect_value(t, win32.WHITENESS, 0x00FF0062) + expect_value(t, win32.NOMIRRORBITMAP, 0x80000000) + expect_value(t, win32.CAPTUREBLT, 0x40000000) + // Region Flags + expect_value(t, win32.ERROR, 0x00000000) + expect_value(t, win32.NULLREGION, 0x00000001) + expect_value(t, win32.SIMPLEREGION, 0x00000002) + expect_value(t, win32.COMPLEXREGION, 0x00000003) + expect_value(t, win32.RGN_ERROR, 0x00000000) + // CombineRgn() Styles + expect_value(t, win32.RGN_AND, 0x00000001) + expect_value(t, win32.RGN_OR, 0x00000002) + expect_value(t, win32.RGN_XOR, 0x00000003) + expect_value(t, win32.RGN_DIFF, 0x00000004) + expect_value(t, win32.RGN_COPY, 0x00000005) + // StretchBlt() Modes + expect_value(t, win32.BLACKONWHITE, 0x00000001) + expect_value(t, win32.WHITEONBLACK, 0x00000002) + expect_value(t, win32.COLORONCOLOR, 0x00000003) + expect_value(t, win32.HALFTONE, 0x00000004) + // PolyFill() Modes + expect_value(t, win32.ALTERNATE, 0x00000001) + expect_value(t, win32.WINDING, 0x00000002) + // Layout Orientation Options + expect_value(t, win32.LAYOUT_RTL, 0x00000001) + expect_value(t, win32.LAYOUT_BTT, 0x00000002) + expect_value(t, win32.LAYOUT_VBH, 0x00000004) + expect_value(t, win32.LAYOUT_ORIENTATIONMASK, 0x00000007) + // Text Alignment Options + expect_value(t, win32.TA_NOUPDATECP, 0x00000000) + expect_value(t, win32.TA_UPDATECP, 0x00000001) + expect_value(t, win32.TA_LEFT, 0x00000000) + expect_value(t, win32.TA_RIGHT, 0x00000002) + expect_value(t, win32.TA_CENTER, 0x00000006) + expect_value(t, win32.TA_TOP, 0x00000000) + expect_value(t, win32.TA_BOTTOM, 0x00000008) + expect_value(t, win32.TA_BASELINE, 0x00000018) + expect_value(t, win32.TA_RTLREADING, 0x00000100) + expect_value(t, win32.TA_MASK, 0x0000011F) +} + +@(test) +verify_winmm :: proc(t: ^testing.T) { + // timeapi.h + expect_size(t, win32.TIMECAPS, 8) + // mmsyscom.h + expect_size(t, win32.MMVERSION, 4) + expect_size(t, win32.MMTIME, 12) + // mmeapi.h + expect_size(t, win32.WAVEFORMATEX, 20) + expect_size(t, win32.WAVEHDR, 48) + expect_size(t, win32.WAVEINCAPSW, 80) + expect_size(t, win32.WAVEOUTCAPSW, 84) +} + +@(test) +verify_advapi32 :: proc(t: ^testing.T) { + // wincrypt.h + expect_size(t, win32.HCRYPTPROV, 8) +} + +@(test) +verify_winnls :: proc(t: ^testing.T) { + // winnls.h + expect_value(t, win32.CP_ACP, 0x00000000) + expect_value(t, win32.CP_OEMCP, 0x00000001) + expect_value(t, win32.CP_MACCP, 0x00000002) + expect_value(t, win32.CP_THREAD_ACP, 0x00000003) + expect_value(t, win32.CP_SYMBOL, 0x0000002A) + expect_value(t, win32.CP_UTF7, 0x0000FDE8) + expect_value(t, win32.CP_UTF8, 0x0000FDE9) + expect_value(t, win32.MAX_DEFAULTCHAR, 0x00000002) + expect_value(t, win32.MAX_LEADBYTES, 0x0000000C) + expect_value(t, win32.LOCALE_NAME_MAX_LENGTH, 0x00000055) + expect_value(t, win32.LOCALE_NAME_USER_DEFAULT, 0x00000000) + expect_value_str(t, win32.LOCALE_NAME_INVARIANT, L("")) + expect_value_str(t, win32.LOCALE_NAME_SYSTEM_DEFAULT, L("!x-sys-default-locale")) + expect_size(t, win32.LCTYPE, 4) + expect_size(t, win32.CPINFOEXW, 544) +} + +@(test) +verify_winreg :: proc(t: ^testing.T) { + // winreg.h + expect_value(t, win32.RRF_RT_REG_NONE, 0x00000001) + expect_value(t, win32.RRF_RT_REG_SZ, 0x00000002) + expect_value(t, win32.RRF_RT_REG_EXPAND_SZ, 0x00000004) + expect_value(t, win32.RRF_RT_REG_BINARY, 0x00000008) + expect_value(t, win32.RRF_RT_REG_DWORD, 0x00000010) + expect_value(t, win32.RRF_RT_REG_MULTI_SZ, 0x00000020) + expect_value(t, win32.RRF_RT_REG_QWORD, 0x00000040) + expect_value(t, win32.RRF_RT_DWORD, 0x00000018) + expect_value(t, win32.RRF_RT_QWORD, 0x00000048) + expect_value(t, win32.RRF_RT_ANY, 0x0000FFFF) + expect_value(t, win32.RRF_NOEXPAND, 0x10000000) + expect_value(t, win32.RRF_ZEROONFAILURE, 0x20000000) + // winnt.h + expect_value(t, u32(win32.HKEY_CLASSES_ROOT), 0x80000000) + expect_value(t, u32(win32.HKEY_CURRENT_USER), 0x80000001) + expect_value(t, u32(win32.HKEY_LOCAL_MACHINE), 0x80000002) + expect_value(t, u32(win32.HKEY_USERS), 0x80000003) + expect_value(t, u32(win32.HKEY_PERFORMANCE_DATA), 0x80000004) + expect_value(t, u32(win32.HKEY_PERFORMANCE_TEXT), 0x80000050) + expect_value(t, u32(win32.HKEY_PERFORMANCE_NLSTEXT), 0x80000060) + expect_value(t, u32(win32.HKEY_CURRENT_CONFIG), 0x80000005) + expect_value(t, u32(win32.HKEY_DYN_DATA), 0x80000006) + expect_value(t, u32(win32.HKEY_CURRENT_USER_LOCAL_SETTINGS), 0x80000007) + expect_value(t, win32.DELETE, 0x00010000) + expect_value(t, win32.READ_CONTROL, 0x00020000) + expect_value(t, win32.WRITE_DAC, 0x00040000) + expect_value(t, win32.WRITE_OWNER, 0x00080000) + expect_value(t, win32.SYNCHRONIZE, 0x00100000) + expect_value(t, win32.KEY_QUERY_VALUE, 0x00000001) + expect_value(t, win32.KEY_SET_VALUE, 0x00000002) + expect_value(t, win32.KEY_CREATE_SUB_KEY, 0x00000004) + expect_value(t, win32.KEY_ENUMERATE_SUB_KEYS, 0x00000008) + expect_value(t, win32.KEY_NOTIFY, 0x00000010) + expect_value(t, win32.KEY_CREATE_LINK, 0x00000020) + expect_value(t, win32.KEY_WOW64_32KEY, 0x00000200) + expect_value(t, win32.KEY_WOW64_64KEY, 0x00000100) + expect_value(t, win32.KEY_WOW64_RES, 0x00000300) + expect_value(t, win32.KEY_READ, 0x00020019) + expect_value(t, win32.KEY_WRITE, 0x00020006) + expect_value(t, win32.KEY_EXECUTE, 0x00020019) + expect_value(t, win32.KEY_ALL_ACCESS, 0x000F003F) +} + +@(test) +verify_verrsrc :: proc(t: ^testing.T) { + // verrsrc.h + expect_value(t, win32.VS_VERSION_INFO, 0x00000001) + expect_value(t, win32.VS_USER_DEFINED, 0x00000064) + expect_size(t, win32.VS_FIXEDFILEINFO, 52) + expect_value(t, win32.VS_FFI_SIGNATURE, 0xFEEF04BD) +} + +@(test) +verify_error_codes :: proc(t: ^testing.T) { + // winerror.h + expect_value(t, win32.ERROR_SUCCESS, 0x00000000) + expect_value(t, win32.NO_ERROR, 0x00000000) + expect_value(t, win32.SEC_E_OK, 0x00000000) + + expect_value(t, win32.ERROR_INVALID_FUNCTION, 0x00000001) + expect_value(t, win32.ERROR_FILE_NOT_FOUND, 0x00000002) + expect_value(t, win32.ERROR_PATH_NOT_FOUND, 0x00000003) + expect_value(t, win32.ERROR_ACCESS_DENIED, 0x00000005) + expect_value(t, win32.ERROR_INVALID_HANDLE, 0x00000006) + expect_value(t, win32.ERROR_NOT_ENOUGH_MEMORY, 0x00000008) + expect_value(t, win32.ERROR_INVALID_BLOCK, 0x00000009) + expect_value(t, win32.ERROR_BAD_ENVIRONMENT, 0x0000000A) + expect_value(t, win32.ERROR_BAD_FORMAT, 0x0000000B) + expect_value(t, win32.ERROR_INVALID_ACCESS, 0x0000000C) + expect_value(t, win32.ERROR_INVALID_DATA, 0x0000000D) + expect_value(t, win32.ERROR_OUTOFMEMORY, 0x0000000E) + expect_value(t, win32.ERROR_INVALID_DRIVE, 0x0000000F) + expect_value(t, win32.ERROR_CURRENT_DIRECTORY, 0x00000010) + expect_value(t, win32.ERROR_NO_MORE_FILES, 0x00000012) + expect_value(t, win32.ERROR_SHARING_VIOLATION, 0x00000020) + expect_value(t, win32.ERROR_LOCK_VIOLATION, 0x00000021) + expect_value(t, win32.ERROR_HANDLE_EOF, 0x00000026) + expect_value(t, win32.ERROR_NOT_SUPPORTED, 0x00000032) + expect_value(t, win32.ERROR_FILE_EXISTS, 0x00000050) + expect_value(t, win32.ERROR_INVALID_PARAMETER, 0x00000057) + expect_value(t, win32.ERROR_BROKEN_PIPE, 0x0000006D) + expect_value(t, win32.ERROR_CALL_NOT_IMPLEMENTED, 0x00000078) + expect_value(t, win32.ERROR_INSUFFICIENT_BUFFER, 0x0000007A) + expect_value(t, win32.ERROR_INVALID_NAME, 0x0000007B) + expect_value(t, win32.ERROR_BAD_ARGUMENTS, 0x000000A0) + expect_value(t, win32.ERROR_LOCK_FAILED, 0x000000A7) + expect_value(t, win32.ERROR_ALREADY_EXISTS, 0x000000B7) + expect_value(t, win32.ERROR_NO_DATA, 0x000000E8) + expect_value(t, win32.ERROR_ENVVAR_NOT_FOUND, 0x000000CB) + expect_value(t, win32.ERROR_OPERATION_ABORTED, 0x000003E3) + expect_value(t, win32.ERROR_IO_PENDING, 0x000003E5) + expect_value(t, win32.ERROR_NO_UNICODE_TRANSLATION, 0x00000459) + expect_value(t, win32.ERROR_TIMEOUT, 0x000005B4) + expect_value(t, win32.ERROR_DATATYPE_MISMATCH, 0x0000065D) + expect_value(t, win32.ERROR_UNSUPPORTED_TYPE, 0x0000065E) + expect_value(t, win32.ERROR_NOT_SAME_OBJECT, 0x00000678) + expect_value(t, win32.ERROR_PIPE_CONNECTED, 0x00000217) + expect_value(t, win32.ERROR_PIPE_BUSY, 0x000000E7) + + expect_value(t, win32.S_OK, 0x00000000) + expect_value(t, win32.E_NOTIMPL, 0x80004001) + expect_value(t, win32.E_NOINTERFACE, 0x80004002) + expect_value(t, win32.E_POINTER, 0x80004003) + expect_value(t, win32.E_ABORT, 0x80004004) + expect_value(t, win32.E_FAIL, 0x80004005) + expect_value(t, win32.E_UNEXPECTED, 0x8000FFFF) + expect_value(t, win32.E_ACCESSDENIED, 0x80070005) + expect_value(t, win32.E_HANDLE, 0x80070006) + expect_value(t, win32.E_OUTOFMEMORY, 0x8007000E) + expect_value(t, win32.E_INVALIDARG, 0x80070057) +} + +@(test) +verify_error_helpers :: proc(t: ^testing.T) { + // winerror.h + expect_value(t, win32.SUCCEEDED(-1), 0x00000000) + expect_value(t, win32.SUCCEEDED(0), 0x00000001) + expect_value(t, win32.SUCCEEDED(1), 0x00000001) + + expect_value(t, win32.FAILED(-1), 0x00000001) + expect_value(t, win32.FAILED(0), 0x00000000) + expect_value(t, win32.FAILED(1), 0x00000000) + + expect_value(t, win32.IS_ERROR(-1), 0x00000001) + expect_value(t, win32.IS_ERROR(0), 0x00000000) + expect_value(t, win32.IS_ERROR(1), 0x00000000) + + expect_value(t, win32.HRESULT_CODE(0xFFFFCCCC), 0x0000CCCC) + expect_value(t, win32.HRESULT_FACILITY(0xFFFFCCCC), 0x00001FFF) + expect_value(t, win32.HRESULT_SEVERITY(0x12345678), 0x00000000) + expect_value(t, win32.HRESULT_SEVERITY(0x87654321), 0x00000001) + + expect_value(t, win32.MAKE_HRESULT(1, 2, 3), 0x80020003) +} diff --git a/tests/core/sys/windows/test_winerror.odin b/tests/core/sys/windows/test_winerror.odin new file mode 100644 index 000000000..adbdb7ce1 --- /dev/null +++ b/tests/core/sys/windows/test_winerror.odin @@ -0,0 +1,34 @@ +//+build windows +package test_core_sys_windows + +import "core:testing" +import win32 "core:sys/windows" + +@(test) +make_hresult :: proc(t: ^testing.T) { + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.SUCCESS, win32.FACILITY.NULL, win32.ERROR_SUCCESS), win32.S_OK) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.NULL, 0x4001), win32.E_NOTIMPL) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.NULL, 0x4002), win32.E_NOINTERFACE) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.NULL, 0x4003), win32.E_POINTER) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.NULL, 0x4004), win32.E_ABORT) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.NULL, 0x4005), win32.E_FAIL) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.NULL, 0xFFFF), win32.E_UNEXPECTED) + + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.WIN32, win32.ERROR_ACCESS_DENIED), win32.E_ACCESSDENIED) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.WIN32, win32.ERROR_INVALID_HANDLE), win32.E_HANDLE) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.WIN32, win32.ERROR_OUTOFMEMORY), win32.E_OUTOFMEMORY) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.WIN32, win32.ERROR_INVALID_PARAMETER), win32.E_INVALIDARG) + + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.WIN32, win32.System_Error.ACCESS_DENIED), win32.E_ACCESSDENIED) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.WIN32, win32.System_Error.INVALID_HANDLE), win32.E_HANDLE) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.WIN32, win32.System_Error.OUTOFMEMORY), win32.E_OUTOFMEMORY) + expect_value(t, win32.MAKE_HRESULT(win32.SEVERITY.ERROR, win32.FACILITY.WIN32, win32.System_Error.INVALID_PARAMETER), win32.E_INVALIDARG) +} + +@(test) +decode_hresult :: proc(t: ^testing.T) { + s, f, c := win32.DECODE_HRESULT(win32.E_INVALIDARG) + expect_value(t, s, win32.SEVERITY.ERROR) + expect_value(t, f, win32.FACILITY.WIN32) + expect_value(t, c, win32.System_Error.INVALID_PARAMETER) +} From 8403952fd20f2f2b8d7add7468e08920861fc4e2 Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Tue, 11 Jun 2024 18:30:41 +0200 Subject: [PATCH 003/122] win32gen --- tests/core/sys/windows/test_kernel32.odin | 10 +- .../sys/windows/test_windows_generated.odin | 7 +- tests/core/sys/windows/win32gen/build.bat | 70 ++ tests/core/sys/windows/win32gen/win32gen.cpp | 932 ++++++++++++++++++ .../sys/windows/win32gen/win32gen.vcxproj | 142 +++ .../windows/win32gen/win32gen.vcxproj.filters | 27 + 6 files changed, 1181 insertions(+), 7 deletions(-) create mode 100644 tests/core/sys/windows/win32gen/build.bat create mode 100644 tests/core/sys/windows/win32gen/win32gen.cpp create mode 100644 tests/core/sys/windows/win32gen/win32gen.vcxproj create mode 100644 tests/core/sys/windows/win32gen/win32gen.vcxproj.filters diff --git a/tests/core/sys/windows/test_kernel32.odin b/tests/core/sys/windows/test_kernel32.odin index 7edc38853..81331fc9f 100644 --- a/tests/core/sys/windows/test_kernel32.odin +++ b/tests/core/sys/windows/test_kernel32.odin @@ -7,16 +7,18 @@ import "core:testing" @(test) lcid_to_local :: proc(t: ^testing.T) { - lcid: win32.LCID = win32.MAKELANGID(0x09, 0x02) + lcid: win32.LCID = win32.MAKELANGID(0x09, win32.SUBLANG_DEFAULT) wname: [512]win32.WCHAR cc := win32.LCIDToLocaleName(lcid, &wname[0], len(wname) - 1, 0) testing.expectf(t, cc == 6, "%#x (should be: %#x)", u32(cc), 6) if cc == 0 {return} str, err := win32.wstring_to_utf8(win32.wstring(&wname), int(cc)) testing.expectf(t, err == .None, "%v (should be: %x)", err, 0) - exp :: "en-GB" + exp :: "en-US" testing.expectf(t, str == exp, "%v (should be: %v)", str, exp) - cc2 := win32.LocaleNameToLCID(L("en-GB"), 0) - testing.expectf(t, cc2 == 0x809, "%#x (should be: %#x)", u32(cc2), 0x809) + cc2 := win32.LocaleNameToLCID(L(exp), 0) + testing.expectf(t, cc2 == 0x0409, "%#x (should be: %#x)", u32(cc2), 0x0409) + + //fmt.printfln("%0X", lcid) } diff --git a/tests/core/sys/windows/test_windows_generated.odin b/tests/core/sys/windows/test_windows_generated.odin index 5c1c74a96..13d09f4e1 100644 --- a/tests/core/sys/windows/test_windows_generated.odin +++ b/tests/core/sys/windows/test_windows_generated.odin @@ -107,7 +107,7 @@ verify_macros :: proc(t: ^testing.T) { expect_value(t, win32.MAKELCID(1, 2), 0x00020001) expect_value(t, win32.MAKELCID(0x1111, 0x2222), 0x22221111) expect_value(t, win32.MAKELANGID(1, 2), 0x00000801) - expect_value(t, win32.MAKELANGID(0x1111, 0x2222), 0x00889911) + expect_value(t, win32.MAKELANGID(0x111, 0x222), 0x00088911) expect_value(t, win32.LANGIDFROMLCID(0x12345678), 0x00005678) } @@ -156,8 +156,9 @@ verify_winuser :: proc(t: ^testing.T) { expect_size(t, win32.HARDWAREINPUT, 8) expect_size(t, win32.INPUT, 40) expect_size(t, win32.ICONINFOEXW, 1080) + expect_size(t, win32.CURSORINFO, 24) + expect_size(t, win32.WINDOWINFO, 60) expect_size(t, win32.RAWINPUTHEADER, 24) - expect_size(t, win32.RAWHID, 12) expect_size(t, win32.RAWMOUSE, 24) expect_size(t, win32.RAWKEYBOARD, 16) expect_size(t, win32.RAWINPUT, 48) @@ -167,7 +168,7 @@ verify_winuser :: proc(t: ^testing.T) { expect_size(t, win32.RID_DEVICE_INFO_KEYBOARD, 24) expect_size(t, win32.RID_DEVICE_INFO_MOUSE, 16) expect_size(t, win32.RID_DEVICE_INFO, 32) - expect_size(t, win32.WINDOWINFO, 60) + expect_value(t, win32.GET_RAWINPUT_CODE_WPARAM(0x12345678), 0x00000078) expect_size(t, win32.DRAWTEXTPARAMS, 20) expect_size(t, win32.BSMINFO, 32) expect_value(t, win32.BROADCAST_QUERY_DENY, 0x424D5144) diff --git a/tests/core/sys/windows/win32gen/build.bat b/tests/core/sys/windows/win32gen/build.bat new file mode 100644 index 000000000..83b2da4a2 --- /dev/null +++ b/tests/core/sys/windows/win32gen/build.bat @@ -0,0 +1,70 @@ +@echo off +if "%VSCMD_ARG_TGT_ARCH%"=="" call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 +set genconfig=Release +pushd %~dp0 + +set genname=win32gen +set cl_output_path=%genname%\x64\%genconfig% +set gen_output_path=x64\%genconfig% +set genexe=%gen_output_path%\%genname%.exe + +if exist "%genexe%" (del /f "%genexe%" > NUL 2> NUL) + +:compiling +echo Compiling... +mkdir %cl_output_path% > NUL 2> NUL +set compiler_flags=^ +/c /Zi /nologo /W3 /WX- ^ +/diagnostics:column /sdl /O2 /Oi /GL ^ +/D NDEBUG /D _CONSOLE /D _UNICODE /D UNICODE ^ +/Gm- /EHsc /MD /GS /Gy /fp:precise ^ +/Zc:wchar_t /Zc:forScope /Zc:inline ^ +/std:c++20 /permissive- /Fo"%cl_output_path%\\" ^ +/external:W3 /Gd /TP /FC /errorReport:queue + +@echo on +cl %compiler_flags% win32gen.cpp +@echo off +if %ERRORLEVEL% NEQ 0 (goto error) + +:linking +echo Linking... +mkdir "%gen_output_path%" > NUL 2> NUL +set libs=^ +kernel32.lib ^ +user32.lib ^ +gdi32.lib ^ +comdlg32.lib ^ +advapi32.lib ^ +shell32.lib ^ +ole32.lib ^ +uuid.lib +set linker_flags=^ +/ERRORREPORT:QUEUE ^ +/OUT:%genexe% ^ +/NOLOGO ^ +%libs% ^ +/MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed ^ +/SUBSYSTEM:CONSOLE ^ +/OPT:REF /OPT:ICF /LTCG:incremental ^ +/LTCGOUT:"%cl_output_path%\%genname%.iobj" ^ +/TLBID:1 /DYNAMICBASE /NXCOMPAT ^ +/IMPLIB:"%gen_output_path%\%genname%.lib" ^ +/MACHINE:X64 + +@echo on +link %linker_flags% %cl_output_path%\%genname%.obj +@echo off +if %ERRORLEVEL% NEQ 0 (goto error) + +:generate +echo Generating... +%genexe% ..\test_windows_generated.odin +goto done + +:error +echo Last command returned %ERRORLEVEL% + +:done +popd +echo Done. diff --git a/tests/core/sys/windows/win32gen/win32gen.cpp b/tests/core/sys/windows/win32gen/win32gen.cpp new file mode 100644 index 000000000..731173aa6 --- /dev/null +++ b/tests/core/sys/windows/win32gen/win32gen.cpp @@ -0,0 +1,932 @@ +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace std::filesystem; + +static std::string ConvertLPCWSTRToString(const LPCWSTR lpcwszStr) +{ + int strLength = WideCharToMultiByte(CP_UTF8, 0, lpcwszStr, -1, nullptr, 0, nullptr, nullptr) - 1; + string str(strLength, 0); + WideCharToMultiByte(CP_UTF8, 0, lpcwszStr, -1, &str[0], strLength, nullptr, nullptr); + return std::string(str); +} + +#define test_proc_begin() out \ + << endl \ + << "@(test)" << endl \ + << __func__ << " :: proc(t: ^testing.T) {" << endl + +#define test_proc_end() out \ + << "}" << endl + +#define test_proc_using(name) out \ + << '\t' << "using " << name << endl + +#define test_proc_comment(comment) out \ + << '\t' << "// " << comment << endl + +#define expect_size(s) out \ + << '\t' << "expect_size(t, win32." << #s << ", " \ + << std::dec << sizeof(s) << ")" << endl + +#define expect_value(s) out \ + << '\t' << "expect_value(t, win32." << #s << ", " \ + << "0x" << std::uppercase << std::setfill('0') << std::setw(8) << std::hex << s << ")" << endl + +#define expect_value_32(s) out \ + << '\t' << "expect_value(t, u32(win32." << #s << "), " \ + << "0x" << std::uppercase << std::setfill('0') << std::setw(8) << std::hex << (ULONG)(ULONG_PTR)(s) << ")" << endl + +#define expect_value_64(s) out \ + << '\t' << "expect_value_64(t, u64(win32." << #s << "), " \ + << "0x" << std::uppercase << std::setfill('0') << std::setw(8) << std::hex << (ULONGLONG)(ULONG_PTR)(s) << ")" << endl + +#define expect_value_uintptr(s) out \ + << '\t' << "expect_value_64(t, uintptr(win32." << #s << "), " \ + << "0x" << std::uppercase << std::setfill('0') << std::setw(8) << std::hex << (ULONG_PTR)(s) << ")" << endl + +#define expect_value_str(s) out \ + << '\t' << "expect_value_str(t, win32." << #s << ", L(\"" << ConvertLPCWSTRToString(s) << "\"))" << endl + +static void verify_win32_type_sizes(ofstream& out) { + test_proc_begin(); + test_proc_comment("minwindef.h"); + expect_size(ULONG); // unsigned long + expect_size(PULONG); // unsigned long* + expect_size(USHORT); // unsigned short + expect_size(PUSHORT); // unsigned short* + expect_size(UCHAR); // unsigned char + // expect_size(PUCHAR); + // expect_size(PSZ); + expect_size(DWORD); // unsigned long + expect_size(BOOL); // int + expect_size(BYTE); // unsigned char + expect_size(WORD); // unsigned short +#ifdef PROPVARIANT + expect_size(FLOAT); // float + expect_size(DOUBLE); // double + expect_size(DATE); // double +#endif + // expect_size(PFLOAT); + expect_size(PBOOL); + expect_size(LPBOOL); + expect_size(PBYTE); + expect_size(LPBYTE); + expect_size(PINT); + expect_size(LPINT); + // expect_size(PWORD); + expect_size(LPWORD); + // expect_size(LPLONG); + expect_size(PDWORD); + expect_size(LPDWORD); + expect_size(LPVOID); + expect_size(LPCVOID); + + expect_size(INT); // int + expect_size(UINT); // unsigned int + expect_size(PUINT); // unsigned int* + + expect_size(UINT_PTR); // unsigned __int64 + expect_size(LONG_PTR); // __int64 + + expect_size(HANDLE); // void * + expect_size(WPARAM); // unsigned __int64 + expect_size(LPARAM); // __int64 + expect_size(LRESULT); // __int64 + + expect_size(LPHANDLE); + expect_size(HGLOBAL); // void * + // expect_size(HLOCAL); + // expect_size(GLOBALHANDLE); + // expect_size(LOCALHANDLE); + + expect_size(ATOM); // unsigned short + expect_size(HKEY); + expect_size(PHKEY); + // expect_size(HMETAFILE); + expect_size(HINSTANCE); + expect_size(HMODULE); + expect_size(HRGN); + expect_size(HRSRC); + // expect_size(HSPRITE); + // expect_size(HLSURF); + // expect_size(HSTR); + // expect_size(HTASK); + // expect_size(HWINSTA); + // expect_size(HKL); + + //expect_size(HFILE); + + test_proc_comment("windef.h"); + expect_size(HWND); + expect_size(HHOOK); + expect_size(HGDIOBJ); + expect_size(HBITMAP); + expect_size(HPALETTE); + expect_size(HBRUSH); + expect_size(HPEN); + expect_size(HFONT); + expect_size(HICON); + expect_size(HMENU); + expect_size(HCURSOR); + expect_size(COLORREF); + expect_size(RECT); + expect_size(POINT); + expect_size(SIZE); + + test_proc_comment("wtypes.h"); + expect_size(DECIMAL); +#ifdef PROPVARIANT + expect_size(CY); +#endif + + test_proc_comment("fileapi.h"); + expect_size(WIN32_FILE_ATTRIBUTE_DATA); + + test_proc_comment("libloaderapi.h"); + expect_size(ENUMRESNAMEPROCW); + expect_size(ENUMRESTYPEPROCW); + + test_proc_comment("minwinbase.h"); + expect_size(SYSTEMTIME); + expect_size(WIN32_FIND_DATAW); + expect_size(CRITICAL_SECTION); + // expect_size(PROCESS_HEAP_ENTRY); + expect_size(REASON_CONTEXT); + + test_proc_comment("guiddef.h"); + expect_size(GUID); + expect_size(IID); + expect_size(CLSID); + test_proc_comment("combaseapi.h"); + expect_size(SCODE); +#ifdef PROPVARIANT + expect_size(VARTYPE); + expect_size(VARIANT_BOOL); + expect_size(CLIPDATA); + expect_size(SAFEARRAYBOUND); + expect_size(SAFEARRAY); + expect_size(CAPROPVARIANT); + expect_size(PROPVARIANT); +#endif + test_proc_comment("commdlg.h"); + expect_size(OPENFILENAMEW); + // test_proc_comment("windns.h"); + // expect_size(DNS_RECORDA); + // expect_size(DNS_RECORDW); + // SHCreateLibrary + test_proc_comment("wtypesbase.h"); + expect_size(OLECHAR); + //test_proc_comment("objbase.h"); + //expect_value(COINIT_MULTITHREADED); + //expect_value(COINIT_APARTMENTTHREADED); + //expect_value(COINIT_DISABLE_OLE1DDE); + //expect_value(COINIT_SPEED_OVER_MEMORY); + test_proc_end(); +} + +static void verify_macros(ofstream& out) { + test_proc_begin(); + test_proc_comment("minwindef.h"); + expect_value(MAKEWORD(1, 2)); + expect_value(MAKEWORD(0x1111, 0x2222)); + expect_value(MAKELONG(1, 2)); + expect_value(MAKELONG(0x1111, 0x2222)); + expect_value(LOWORD(0x12345678)); + expect_value(HIWORD(0x12345678)); + expect_value_32(LOBYTE(0x1234)); + expect_value_32(HIBYTE(0x1234)); + test_proc_comment("winuser.h"); + expect_value(MAKEWPARAM(1, 2)); + expect_value(MAKEWPARAM(0x1111, 0x2222)); + expect_value(MAKELPARAM(1, 2)); + expect_value(MAKELPARAM(0x1111, 0x2222)); + expect_value(MAKELRESULT(1, 2)); + expect_value(MAKELRESULT(0x1111, 0x2222)); + test_proc_comment("winnt.h"); + expect_value(MAKELCID(1, 2)); + expect_value(MAKELCID(0x1111, 0x2222)); + expect_value(MAKELANGID(1, 2)); + expect_value(MAKELANGID(0x111, 0x222)); + expect_value(LANGIDFROMLCID(0x12345678)); + test_proc_end(); +} + +static void verify_winnt(ofstream& out) { + test_proc_begin(); + test_proc_comment("winnt.h"); + expect_size(CHAR); + expect_size(SHORT); + expect_size(LONG); + expect_size(INT); + expect_size(WCHAR); + // expect_size(LONGLONG); + expect_size(ULONGLONG); + expect_size(LARGE_INTEGER); + expect_size(PLARGE_INTEGER); + expect_size(ULARGE_INTEGER); + expect_size(PULARGE_INTEGER); + expect_size(BOOLEAN); + expect_size(HANDLE); + expect_size(PHANDLE); + expect_size(HRESULT); + // expect_size(CCHAR); + expect_size(LCID); + expect_size(LANGID); + + expect_size(LUID); + expect_size(SECURITY_INFORMATION); + expect_size(ACCESS_MASK); + expect_size(REGSAM); + expect_value(LANG_NEUTRAL); + expect_value(LANG_INVARIANT); + expect_value(SUBLANG_NEUTRAL); + expect_value(SUBLANG_DEFAULT); + test_proc_end(); +} + +static void verify_winuser(ofstream& out) { + test_proc_begin(); + test_proc_comment("winuser.h"); + //expect_value(UOI_FLAGS); + expect_size(USEROBJECTFLAGS); + expect_size(MSG); + expect_size(WINDOWPOS); + expect_size(ACCEL); + expect_size(MENUITEMINFOW); + expect_size(PAINTSTRUCT); + expect_size(CREATESTRUCTW); + expect_size(WINDOWPLACEMENT); + expect_size(MOUSEINPUT); + expect_size(KEYBDINPUT); + expect_size(HARDWAREINPUT); + expect_size(INPUT); + + // expect_size(ICONINFO); + // expect_size(CURSORSHAPE); + expect_size(ICONINFOEXW); + + expect_size(CURSORINFO); + //expect_value(CURSOR_SHOWING); + //expect_value(CURSOR_SUPPRESSED); + + expect_size(WINDOWINFO); + + expect_size(RAWINPUTHEADER); + //expect_size(RAWHID); + expect_size(RAWMOUSE); + expect_size(RAWKEYBOARD); + expect_size(RAWINPUT); + expect_size(RAWINPUTDEVICE); + expect_size(RAWINPUTDEVICELIST); + + expect_size(RID_DEVICE_INFO_HID); + expect_size(RID_DEVICE_INFO_KEYBOARD); + expect_size(RID_DEVICE_INFO_MOUSE); + expect_size(RID_DEVICE_INFO); + expect_value(GET_RAWINPUT_CODE_WPARAM(0x12345678)); + + expect_size(DRAWTEXTPARAMS); + expect_size(BSMINFO); + + expect_value(BROADCAST_QUERY_DENY); + expect_value_64(HWND_BROADCAST); + expect_value_64(HWND_MESSAGE); + + expect_value_uintptr(MAKEINTRESOURCEW(1)); + expect_value_uintptr(MAKEINTRESOURCEW(0x12345678)); + + expect_value_uintptr(RT_CURSOR); + expect_value_uintptr(RT_BITMAP); + expect_value_uintptr(RT_ICON); + expect_value_uintptr(RT_MENU); + expect_value_uintptr(RT_DIALOG); + expect_value_uintptr(RT_STRING); + expect_value_uintptr(RT_FONTDIR); + expect_value_uintptr(RT_FONT); + expect_value_uintptr(RT_ACCELERATOR); + expect_value_uintptr(RT_RCDATA); + expect_value_uintptr(RT_MESSAGETABLE); + expect_value_uintptr(RT_GROUP_CURSOR); + expect_value_uintptr(RT_GROUP_ICON); + expect_value_uintptr(RT_VERSION); + expect_value_uintptr(RT_DLGINCLUDE); + expect_value_uintptr(RT_PLUGPLAY); + expect_value_uintptr(RT_VXD); + expect_value_uintptr(RT_ANICURSOR); + expect_value_uintptr(RT_ANIICON); + expect_value_uintptr(RT_MANIFEST); + + expect_value_uintptr(CREATEPROCESS_MANIFEST_RESOURCE_ID); + expect_value_uintptr(ISOLATIONAWARE_MANIFEST_RESOURCE_ID); + expect_value_uintptr(ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID); + expect_value_uintptr(ISOLATIONPOLICY_MANIFEST_RESOURCE_ID); + expect_value_uintptr(ISOLATIONPOLICY_BROWSER_MANIFEST_RESOURCE_ID); + expect_value_uintptr(MINIMUM_RESERVED_MANIFEST_RESOURCE_ID); + expect_value_uintptr(MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID); + + expect_value(SM_CXICON); + expect_value(SM_CYICON); + + expect_value(LR_DEFAULTCOLOR); + expect_value(LR_MONOCHROME); + expect_value(LR_COLOR); + expect_value(LR_COPYRETURNORG); + expect_value(LR_COPYDELETEORG); + expect_value(LR_LOADFROMFILE); + expect_value(LR_LOADTRANSPARENT); + expect_value(LR_DEFAULTSIZE); + expect_value(LR_VGACOLOR); + expect_value(LR_LOADMAP3DCOLORS); + expect_value(LR_CREATEDIBSECTION); + expect_value(LR_COPYFROMRESOURCE); + expect_value(LR_SHARED); + + expect_value(NIM_ADD); + expect_value(NIM_MODIFY); + expect_value(NIM_DELETE); + expect_value(NIM_SETFOCUS); + expect_value(NIM_SETVERSION); + + expect_value(NIF_MESSAGE); + expect_value(NIF_ICON); + expect_value(NIF_TIP); + expect_value(NIF_STATE); + expect_value(NIF_INFO); + expect_value(NIF_GUID); + expect_value(NIF_REALTIME); + expect_value(NIF_SHOWTIP); + + expect_value(MF_INSERT); + expect_value(MF_CHANGE); + expect_value(MF_APPEND); + expect_value(MF_DELETE); + expect_value(MF_REMOVE); + expect_value(MF_BYCOMMAND); + expect_value(MF_BYPOSITION); + expect_value(MF_SEPARATOR); + expect_value(MF_ENABLED); + expect_value(MF_GRAYED); + expect_value(MF_DISABLED); + expect_value(MF_UNCHECKED); + expect_value(MF_CHECKED); + expect_value(MF_USECHECKBITMAPS); + expect_value(MF_STRING); + expect_value(MF_BITMAP); + expect_value(MF_OWNERDRAW); + expect_value(MF_POPUP); + expect_value(MF_MENUBARBREAK); + expect_value(MF_MENUBREAK); + expect_value(MF_UNHILITE); + expect_value(MF_HILITE); + expect_value(MF_DEFAULT); + expect_value(MF_SYSMENU); + expect_value(MF_HELP); + expect_value(MF_RIGHTJUSTIFY); + expect_value(MF_MOUSESELECT); + expect_value(MF_END); + + expect_value(MFS_GRAYED); + expect_value(MFS_DISABLED); + expect_value(MFS_CHECKED); + expect_value(MFS_HILITE); + expect_value(MFS_ENABLED); + expect_value(MFS_UNCHECKED); + expect_value(MFS_UNHILITE); + expect_value(MFS_DEFAULT); + + expect_value(TPM_LEFTBUTTON); + expect_value(TPM_RIGHTBUTTON); + expect_value(TPM_LEFTALIGN); + expect_value(TPM_CENTERALIGN); + expect_value(TPM_RIGHTALIGN); + expect_value(TPM_TOPALIGN); + expect_value(TPM_VCENTERALIGN); + expect_value(TPM_BOTTOMALIGN); + + expect_value(TPM_HORIZONTAL); + expect_value(TPM_VERTICAL); + expect_value(TPM_NONOTIFY); + expect_value(TPM_RETURNCMD); + expect_value(TPM_RECURSE); + expect_value(TPM_HORPOSANIMATION); + expect_value(TPM_HORNEGANIMATION); + expect_value(TPM_VERPOSANIMATION); + expect_value(TPM_VERNEGANIMATION); + expect_value(TPM_NOANIMATION); + expect_value(TPM_LAYOUTRTL); + expect_value(TPM_WORKAREA); + + expect_value(MIIM_STATE); + expect_value(MIIM_ID); + expect_value(MIIM_SUBMENU); + expect_value(MIIM_CHECKMARKS); + expect_value(MIIM_TYPE); + expect_value(MIIM_DATA); + expect_value(MIIM_STRING); + expect_value(MIIM_BITMAP); + expect_value(MIIM_FTYPE); + + expect_value(ANSI_CHARSET); + expect_value(DEFAULT_CHARSET); + expect_value(SYMBOL_CHARSET); + expect_value(SHIFTJIS_CHARSET); + expect_value(HANGEUL_CHARSET); + expect_value(HANGUL_CHARSET); + expect_value(GB2312_CHARSET); + expect_value(CHINESEBIG5_CHARSET); + expect_value(OEM_CHARSET); + expect_value(JOHAB_CHARSET); + expect_value(HEBREW_CHARSET); + expect_value(ARABIC_CHARSET); + expect_value(GREEK_CHARSET); + expect_value(TURKISH_CHARSET); + expect_value(VIETNAMESE_CHARSET); + expect_value(THAI_CHARSET); + expect_value(EASTEUROPE_CHARSET); + expect_value(RUSSIAN_CHARSET); + expect_value(MAC_CHARSET); + expect_value(BALTIC_CHARSET); + + expect_value(FS_LATIN1); + expect_value(FS_LATIN2); + expect_value(FS_CYRILLIC); + expect_value(FS_GREEK); + expect_value(FS_TURKISH); + expect_value(FS_HEBREW); + expect_value(FS_ARABIC); + expect_value(FS_BALTIC); + expect_value(FS_VIETNAMESE); + expect_value(FS_THAI); + expect_value(FS_JISJAPAN); + expect_value(FS_CHINESESIMP); + expect_value(FS_WANSUNG); + expect_value(FS_CHINESETRAD); + expect_value(FS_JOHAB); + expect_value(FS_SYMBOL); + + expect_value(OUT_DEFAULT_PRECIS); + expect_value(OUT_STRING_PRECIS); + expect_value(OUT_CHARACTER_PRECIS); + expect_value(OUT_STROKE_PRECIS); + expect_value(OUT_TT_PRECIS); + expect_value(OUT_DEVICE_PRECIS); + expect_value(OUT_RASTER_PRECIS); + expect_value(OUT_TT_ONLY_PRECIS); + expect_value(OUT_OUTLINE_PRECIS); + expect_value(OUT_SCREEN_OUTLINE_PRECIS); + expect_value(OUT_PS_ONLY_PRECIS); + + expect_value(CLIP_DEFAULT_PRECIS); + expect_value(CLIP_CHARACTER_PRECIS); + expect_value(CLIP_STROKE_PRECIS); + expect_value(CLIP_MASK); + expect_value(CLIP_LH_ANGLES); + expect_value(CLIP_TT_ALWAYS); + expect_value(CLIP_DFA_DISABLE); + expect_value(CLIP_EMBEDDED); + + expect_value(DEFAULT_QUALITY); + expect_value(DRAFT_QUALITY); + expect_value(PROOF_QUALITY); + expect_value(NONANTIALIASED_QUALITY); + expect_value(ANTIALIASED_QUALITY); + expect_value(CLEARTYPE_QUALITY); + expect_value(CLEARTYPE_NATURAL_QUALITY); + + expect_value(DEFAULT_PITCH); + expect_value(FIXED_PITCH); + expect_value(VARIABLE_PITCH); + expect_value(MONO_FONT); + + expect_value(FF_DONTCARE); + expect_value(FF_ROMAN); + expect_value(FF_SWISS); + expect_value(FF_MODERN); + expect_value(FF_SCRIPT); + expect_value(FF_DECORATIVE); + + test_proc_end(); +} + +static void verify_gdi32(ofstream& out) { + test_proc_begin(); + test_proc_comment("wingdi.h"); + expect_size(DEVMODEW); + // expect_size(RGBTRIPLE); + expect_size(RGBQUAD); + expect_size(PIXELFORMATDESCRIPTOR); + expect_size(BITMAPINFOHEADER); + expect_size(BITMAP); + expect_size(BITMAPV5HEADER); + expect_size(CIEXYZTRIPLE); + expect_size(CIEXYZ); + expect_size(FXPT2DOT30); + expect_size(TEXTMETRICW); + expect_size(POINTFLOAT); + expect_size(GLYPHMETRICSFLOAT); + // expect_size(LOGPALETTE); + expect_size(PALETTEENTRY); + expect_size(DESIGNVECTOR); + expect_value(LF_FACESIZE); + expect_value(LF_FULLFACESIZE); + expect_size(LOGFONTW); + expect_size(ENUMLOGFONTW); + expect_size(ENUMLOGFONTEXW); + expect_size(ENUMLOGFONTEXDVW); + expect_size(NEWTEXTMETRICW); + + expect_size(LAYERPLANEDESCRIPTOR); + expect_size(COLOR16); + expect_size(TRIVERTEX); + expect_size(GRADIENT_TRIANGLE); + expect_size(GRADIENT_RECT); + expect_size(BLENDFUNCTION); + expect_size(DISPLAY_DEVICEW); + expect_value(AC_SRC_OVER); + expect_value(AC_SRC_ALPHA); + expect_value(RGB(12, 34, 56)); + expect_value(PALETTERGB(12, 34, 56)); + expect_value(PALETTEINDEX(123)); + expect_value(GRADIENT_FILL_RECT_H); + expect_value(GRADIENT_FILL_RECT_V); + expect_value(GRADIENT_FILL_TRIANGLE); + + expect_value(BS_SOLID); + expect_value(BS_NULL); + expect_value(BS_HOLLOW); + expect_value(BS_HATCHED); + expect_value(BS_PATTERN); + expect_value(BS_INDEXED); + expect_value(BS_DIBPATTERN); + expect_value(BS_DIBPATTERNPT); + expect_value(BS_PATTERN8X8); + expect_value(BS_DIBPATTERN8X8); + expect_value(BS_MONOPATTERN); + + expect_value(HS_HORIZONTAL); + expect_value(HS_VERTICAL); + expect_value(HS_FDIAGONAL); + expect_value(HS_BDIAGONAL); + expect_value(HS_CROSS); + expect_value(HS_DIAGCROSS); + expect_value(HS_API_MAX); + + expect_value(PS_SOLID); + expect_value(PS_DASH); + expect_value(PS_DOT); + expect_value(PS_DASHDOT); + expect_value(PS_DASHDOTDOT); + expect_value(PS_NULL); + expect_value(PS_INSIDEFRAME); + expect_value(PS_USERSTYLE); + expect_value(PS_ALTERNATE); + expect_value(PS_STYLE_MASK); + + expect_value(PS_ENDCAP_ROUND); + expect_value(PS_ENDCAP_SQUARE); + expect_value(PS_ENDCAP_FLAT); + expect_value(PS_ENDCAP_MASK); + + expect_value(PS_JOIN_ROUND); + expect_value(PS_JOIN_BEVEL); + expect_value(PS_JOIN_MITER); + + expect_value(PS_COSMETIC); + expect_value(PS_GEOMETRIC); + expect_value(PS_TYPE_MASK); + + test_proc_comment("Binary raster ops"); + expect_value(R2_BLACK); + expect_value(R2_NOTMERGEPEN); + expect_value(R2_MASKNOTPEN); + expect_value(R2_NOTCOPYPEN); + expect_value(R2_MASKPENNOT); + expect_value(R2_NOT); + expect_value(R2_XORPEN); + expect_value(R2_NOTMASKPEN); + expect_value(R2_MASKPEN); + expect_value(R2_NOTXORPEN); + expect_value(R2_NOP); + expect_value(R2_MERGENOTPEN); + expect_value(R2_COPYPEN); + expect_value(R2_MERGEPENNOT); + expect_value(R2_MERGEPEN); + expect_value(R2_WHITE); + test_proc_comment("Ternary raster operations"); + expect_value(SRCCOPY); + expect_value(SRCPAINT); + expect_value(SRCAND); + expect_value(SRCINVERT); + expect_value(SRCERASE); + expect_value(NOTSRCCOPY); + expect_value(NOTSRCERASE); + expect_value(MERGECOPY); + expect_value(MERGEPAINT); + expect_value(PATCOPY); + expect_value(PATPAINT); + expect_value(PATINVERT); + expect_value(DSTINVERT); + expect_value(BLACKNESS); + expect_value(WHITENESS); + expect_value(NOMIRRORBITMAP); + expect_value(CAPTUREBLT); + test_proc_comment("Region Flags"); + expect_value(ERROR); + expect_value(NULLREGION); + expect_value(SIMPLEREGION); + expect_value(COMPLEXREGION); + expect_value(RGN_ERROR); + test_proc_comment("CombineRgn() Styles"); + expect_value(RGN_AND); + expect_value(RGN_OR); + expect_value(RGN_XOR); + expect_value(RGN_DIFF); + expect_value(RGN_COPY); + test_proc_comment("StretchBlt() Modes"); + expect_value(BLACKONWHITE); + expect_value(WHITEONBLACK); + expect_value(COLORONCOLOR); + expect_value(HALFTONE); + //expect_value(STRETCH_ANDSCANS); + //expect_value(STRETCH_ORSCANS); + //expect_value(STRETCH_DELETESCANS); + //expect_value(STRETCH_HALFTONE); + test_proc_comment("PolyFill() Modes"); + expect_value(ALTERNATE); + expect_value(WINDING); + test_proc_comment("Layout Orientation Options"); + expect_value(LAYOUT_RTL); + expect_value(LAYOUT_BTT); + expect_value(LAYOUT_VBH); + expect_value(LAYOUT_ORIENTATIONMASK); + test_proc_comment("Text Alignment Options"); + expect_value(TA_NOUPDATECP); + expect_value(TA_UPDATECP); + expect_value(TA_LEFT); + expect_value(TA_RIGHT); + expect_value(TA_CENTER); + expect_value(TA_TOP); + expect_value(TA_BOTTOM); + expect_value(TA_BASELINE); + expect_value(TA_RTLREADING); + expect_value(TA_MASK); + test_proc_end(); +} + +static void verify_winmm(ofstream& out) { + test_proc_begin(); + test_proc_comment("timeapi.h"); + expect_size(TIMECAPS); + test_proc_comment("mmsyscom.h"); + expect_size(MMVERSION); + expect_size(MMTIME); + test_proc_comment("mmeapi.h"); + expect_size(WAVEFORMATEX); + expect_size(WAVEHDR); + expect_size(WAVEINCAPSW); + expect_size(WAVEOUTCAPSW); + test_proc_end(); +} + +static void verify_advapi32(ofstream& out) { + test_proc_begin(); + test_proc_comment("wincrypt.h"); + expect_size(HCRYPTPROV); + test_proc_end(); +} + +static void verify_winnls(ofstream& out) { + test_proc_begin(); + test_proc_comment("winnls.h"); + expect_value(CP_ACP); + expect_value(CP_OEMCP); + expect_value(CP_MACCP); + expect_value(CP_THREAD_ACP); + expect_value(CP_SYMBOL); + expect_value(CP_UTF7); + expect_value(CP_UTF8); + expect_value(MAX_DEFAULTCHAR); + expect_value(MAX_LEADBYTES); + expect_value(LOCALE_NAME_MAX_LENGTH); + expect_value(LOCALE_NAME_USER_DEFAULT); + expect_value_str(LOCALE_NAME_INVARIANT); + expect_value_str(LOCALE_NAME_SYSTEM_DEFAULT); + expect_size(LCTYPE); + expect_size(CPINFOEXW); + test_proc_end(); +} + +static void verify_winreg(ofstream& out) { + test_proc_begin(); + test_proc_comment("winreg.h"); + + expect_value(RRF_RT_REG_NONE); + expect_value(RRF_RT_REG_SZ); + expect_value(RRF_RT_REG_EXPAND_SZ); + expect_value(RRF_RT_REG_BINARY); + expect_value(RRF_RT_REG_DWORD); + expect_value(RRF_RT_REG_MULTI_SZ); + expect_value(RRF_RT_REG_QWORD); + expect_value(RRF_RT_DWORD); + expect_value(RRF_RT_QWORD); + expect_value(RRF_RT_ANY); + expect_value(RRF_NOEXPAND); + expect_value(RRF_ZEROONFAILURE); + + test_proc_comment("winnt.h"); + expect_value_32(HKEY_CLASSES_ROOT); + expect_value_32(HKEY_CURRENT_USER); + expect_value_32(HKEY_LOCAL_MACHINE); + expect_value_32(HKEY_USERS); + expect_value_32(HKEY_PERFORMANCE_DATA); + expect_value_32(HKEY_PERFORMANCE_TEXT); + expect_value_32(HKEY_PERFORMANCE_NLSTEXT); + expect_value_32(HKEY_CURRENT_CONFIG); + expect_value_32(HKEY_DYN_DATA); + expect_value_32(HKEY_CURRENT_USER_LOCAL_SETTINGS); + + expect_value(DELETE); + expect_value(READ_CONTROL); + expect_value(WRITE_DAC); + expect_value(WRITE_OWNER); + expect_value(SYNCHRONIZE); + + expect_value(KEY_QUERY_VALUE); + expect_value(KEY_SET_VALUE); + expect_value(KEY_CREATE_SUB_KEY); + expect_value(KEY_ENUMERATE_SUB_KEYS); + expect_value(KEY_NOTIFY); + expect_value(KEY_CREATE_LINK); + expect_value(KEY_WOW64_32KEY); + expect_value(KEY_WOW64_64KEY); + expect_value(KEY_WOW64_RES); + expect_value(KEY_READ); + expect_value(KEY_WRITE); + expect_value(KEY_EXECUTE); + expect_value(KEY_ALL_ACCESS); + + // RegQueryInfoKey + test_proc_end(); +} + +static void verify_verrsrc(ofstream& out) { + test_proc_begin(); + test_proc_comment("verrsrc.h"); + //expect_value_64(VS_FILE_INFO); + expect_value(VS_VERSION_INFO); + expect_value(VS_USER_DEFINED); + expect_size(VS_FIXEDFILEINFO); + // expect_value(VS_FF_DEBUG); + // expect_value(VS_FF_PRERELEASE); + // expect_value(VS_FF_PATCHED); + expect_value(VS_FFI_SIGNATURE); + // VFF_DEBUG + // VFT_WINDOWS_DRV + // VFT_WINDOWS_DLL + test_proc_end(); +} + +static void verify_error_codes(ofstream& out) { + test_proc_begin(); + test_proc_comment("winerror.h"); + + expect_value(ERROR_SUCCESS); + expect_value(NO_ERROR); + expect_value(SEC_E_OK); + out << endl; + expect_value(ERROR_INVALID_FUNCTION); + expect_value(ERROR_FILE_NOT_FOUND); + expect_value(ERROR_PATH_NOT_FOUND); + expect_value(ERROR_ACCESS_DENIED); + expect_value(ERROR_INVALID_HANDLE); + expect_value(ERROR_NOT_ENOUGH_MEMORY); + expect_value(ERROR_INVALID_BLOCK); + expect_value(ERROR_BAD_ENVIRONMENT); + expect_value(ERROR_BAD_FORMAT); + expect_value(ERROR_INVALID_ACCESS); + expect_value(ERROR_INVALID_DATA); + expect_value(ERROR_OUTOFMEMORY); + expect_value(ERROR_INVALID_DRIVE); + expect_value(ERROR_CURRENT_DIRECTORY); + expect_value(ERROR_NO_MORE_FILES); + expect_value(ERROR_SHARING_VIOLATION); + expect_value(ERROR_LOCK_VIOLATION); + expect_value(ERROR_HANDLE_EOF); + expect_value(ERROR_NOT_SUPPORTED); + expect_value(ERROR_FILE_EXISTS); + expect_value(ERROR_INVALID_PARAMETER); + expect_value(ERROR_BROKEN_PIPE); + expect_value(ERROR_CALL_NOT_IMPLEMENTED); + expect_value(ERROR_INSUFFICIENT_BUFFER); + expect_value(ERROR_INVALID_NAME); + expect_value(ERROR_BAD_ARGUMENTS); + expect_value(ERROR_LOCK_FAILED); + expect_value(ERROR_ALREADY_EXISTS); + expect_value(ERROR_NO_DATA); + expect_value(ERROR_ENVVAR_NOT_FOUND); + expect_value(ERROR_OPERATION_ABORTED); + expect_value(ERROR_IO_PENDING); + expect_value(ERROR_NO_UNICODE_TRANSLATION); + expect_value(ERROR_TIMEOUT); + expect_value(ERROR_DATATYPE_MISMATCH); + expect_value(ERROR_UNSUPPORTED_TYPE); + expect_value(ERROR_NOT_SAME_OBJECT); + expect_value(ERROR_PIPE_CONNECTED); + expect_value(ERROR_PIPE_BUSY); + out << endl; + expect_value(S_OK); + expect_value(E_NOTIMPL); + expect_value(E_NOINTERFACE); + expect_value(E_POINTER); + expect_value(E_ABORT); + expect_value(E_FAIL); + expect_value(E_UNEXPECTED); + expect_value(E_ACCESSDENIED); + expect_value(E_HANDLE); + expect_value(E_OUTOFMEMORY); + expect_value(E_INVALIDARG); + // out << endl; + // expect_value(SEVERITY_SUCCESS); + // expect_value(SEVERITY_ERROR); + // out << endl; + // expect_value(FACILITY_NULL); + test_proc_end(); +} + +static void verify_error_helpers(ofstream& out) { + test_proc_begin(); + test_proc_comment("winerror.h"); + + expect_value(SUCCEEDED(-1)); + expect_value(SUCCEEDED(0)); + expect_value(SUCCEEDED(1)); + out << endl; + expect_value(FAILED(-1)); + expect_value(FAILED(0)); + expect_value(FAILED(1)); + out << endl; + expect_value(IS_ERROR(-1)); + expect_value(IS_ERROR(0)); + expect_value(IS_ERROR(1)); + out << endl; + expect_value(HRESULT_CODE(0xFFFFCCCC)); + expect_value(HRESULT_FACILITY(0xFFFFCCCC)); + expect_value(HRESULT_SEVERITY(0x12345678)); + expect_value(HRESULT_SEVERITY(0x87654321)); + out << endl; + expect_value(MAKE_HRESULT(1, 2, 3)); + + test_proc_end(); +} + +static void test_core_sys_windows(ofstream& out) { + out << "//+build windows" << endl + << "package " << __func__ + << " // generated by " << path(__FILE__).filename().replace_extension("").string() << endl + << endl + << "import \"core:testing\"" << endl + << "import win32 \"core:sys/windows\"" << endl; + verify_win32_type_sizes(out); + verify_macros(out); + verify_winnt(out); + verify_winuser(out); + verify_gdi32(out); + verify_winmm(out); + verify_advapi32(out); + verify_winnls(out); + verify_winreg(out); + verify_verrsrc(out); + verify_error_codes(out); + verify_error_helpers(out); +} + +int main(int argc, char* argv[]) { + if (argc < 2) { cout << "Usage: " << path(argv[0]).filename().string() << " " << endl; return -1; } + auto filepath = path(argv[1]); + cout << "Writing " << filepath.string() << endl; + ofstream out(filepath); + test_core_sys_windows(out); + out.close(); +} diff --git a/tests/core/sys/windows/win32gen/win32gen.vcxproj b/tests/core/sys/windows/win32gen/win32gen.vcxproj new file mode 100644 index 000000000..33c44c989 --- /dev/null +++ b/tests/core/sys/windows/win32gen/win32gen.vcxproj @@ -0,0 +1,142 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {a31ceb6a-3f6f-4db6-82ce-8892efa48982} + win32console + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/core/sys/windows/win32gen/win32gen.vcxproj.filters b/tests/core/sys/windows/win32gen/win32gen.vcxproj.filters new file mode 100644 index 000000000..30cdcd8c6 --- /dev/null +++ b/tests/core/sys/windows/win32gen/win32gen.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Source Files + + + \ No newline at end of file From 3291c59728f298a725c815118311e385a9d1e059 Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Thu, 11 Jul 2024 21:37:37 +0200 Subject: [PATCH 004/122] post rebase --- core/sys/windows/kernel32.odin | 30 +++++------------------------- core/sys/windows/user32.odin | 5 +---- 2 files changed, 6 insertions(+), 29 deletions(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index c2f97fff9..bb4cf2619 100755 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -51,14 +51,10 @@ foreign kernel32 { // https://learn.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents GetNumberOfConsoleInputEvents :: proc(hConsoleInput: HANDLE, lpcNumberOfEvents: LPDWORD) -> BOOL --- - GetConsoleMode :: proc(hConsoleHandle: HANDLE, - lpMode: LPDWORD) -> BOOL --- - SetConsoleMode :: proc(hConsoleHandle: HANDLE, - dwMode: DWORD) -> BOOL --- - SetConsoleCursorPosition :: proc(hConsoleHandle: HANDLE, - dwCursorPosition: COORD) -> BOOL --- - SetConsoleTextAttribute :: proc(hConsoleOutput: HANDLE, - wAttributes: WORD) -> BOOL --- + GetConsoleMode :: proc(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL --- + SetConsoleMode :: proc(hConsoleHandle: HANDLE, dwMode: DWORD) -> BOOL --- + SetConsoleCursorPosition :: proc(hConsoleHandle: HANDLE, dwCursorPosition: COORD) -> BOOL --- + SetConsoleTextAttribute :: proc(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL --- GetConsoleCP :: proc() -> CODEPAGE --- SetConsoleCP :: proc(wCodePageID: CODEPAGE) -> BOOL --- GetConsoleOutputCP :: proc() -> CODEPAGE --- @@ -446,7 +442,7 @@ foreign kernel32 { AddDllDirectory :: proc(NewDirectory: PCWSTR) -> rawptr --- RemoveDllDirectory :: proc(Cookie: rawptr) -> BOOL --- LoadLibraryW :: proc(c_str: LPCWSTR) -> HMODULE --- - LoadLibraryExW :: proc(c_str: LPCWSTR, hFile: HANDLE, dwFlags: LOAD_LIBRARY_FLAGS) -> HMODULE --- + LoadLibraryExW :: proc(c_str: LPCWSTR, hFile: HANDLE, dwFlags: LoadLibraryEx_Flags) -> HMODULE --- FreeLibrary :: proc(h: HMODULE) -> BOOL --- GetProcAddress :: proc(h: HMODULE, c_str: LPCSTR) -> rawptr --- @@ -1163,20 +1159,4 @@ GMEM_INVALID_HANDLE :: 0x8000 GHND :: (GMEM_MOVEABLE | GMEM_ZEROINIT) GPTR :: (GMEM_FIXED | GMEM_ZEROINIT) -LOAD_LIBRARY_FLAGS :: enum DWORD { - DONT_RESOLVE_DLL_REFERENCES = 0x00000001, - LOAD_LIBRARY_AS_DATAFILE = 0x00000002, - // reserved for internal LOAD_PACKAGED_LIBRARY = 0x00000004, - LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008, - LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010, - LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020, - LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040, - LOAD_LIBRARY_REQUIRE_SIGNED_TARGET = 0x00000080, - LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100, - LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200, - LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400, - LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800, - LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000, -} - LPTOP_LEVEL_EXCEPTION_FILTER :: PVECTORED_EXCEPTION_HANDLER diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 0ad479dd8..96ccb7dda 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -37,10 +37,7 @@ foreign user32 { lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, - X: INT, - Y: INT, - nWidth: INT, - nHeight: INT, + X, Y, nWidth, nHeight: INT, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, From f78a792d4802be386a8798de100e17649ca2c3fd Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 20 Jul 2024 18:30:41 +0200 Subject: [PATCH 005/122] Add Lua example to vendor\lua as well as basic tests. --- tests/vendor/all.odin | 1 + tests/vendor/lua/5.4/factorial.lua | 10 +++ tests/vendor/lua/5.4/test_vendor_lua.5.4.odin | 71 +++++++++++++++++++ vendor/lua/README.md | 48 +++++++++++-- 4 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 tests/vendor/lua/5.4/factorial.lua create mode 100644 tests/vendor/lua/5.4/test_vendor_lua.5.4.odin diff --git a/tests/vendor/all.odin b/tests/vendor/all.odin index 1ce56e786..1abbc5d7f 100644 --- a/tests/vendor/all.odin +++ b/tests/vendor/all.odin @@ -1,3 +1,4 @@ package tests_vendor @(require) import "glfw" +@(require) import "lua/5.4" \ No newline at end of file diff --git a/tests/vendor/lua/5.4/factorial.lua b/tests/vendor/lua/5.4/factorial.lua new file mode 100644 index 000000000..00cfb20f7 --- /dev/null +++ b/tests/vendor/lua/5.4/factorial.lua @@ -0,0 +1,10 @@ +-- defines a factorial function +function fact (n) + if n == 0 then + return 1 + else + return n * fact(n-1) + end +end + +return fact(10) \ No newline at end of file diff --git a/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin b/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin new file mode 100644 index 000000000..5cfc2cefa --- /dev/null +++ b/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin @@ -0,0 +1,71 @@ +//+build windows, linux, darwin +package test_vendor_lua_54 + +import "core:testing" +import "core:c" +import lua "vendor:lua/5.4" +import "base:runtime" + +@(test) +// Test context.allocator and returning a string +return_string_with_context_based_allocator :: proc(t: ^testing.T) { + _context := context + + state: ^lua.State + state = lua.newstate(lua_context_allocator, &_context) + defer lua.close(state) + + lua.L_dostring(state, "return 'somestring'") + str := lua.tostring(state, -1) + + testing.expectf( + t, str == "somestring", "Expected Lua to return \"somestring\"", + ) +} + +@(test) +// Test lua.dofile and returning an integer +dofile_factorial :: proc(t: ^testing.T) { + state := lua.L_newstate() + defer lua.close(state) + + FACT_10 :: 3628800 + + res := lua.L_dofile(state, "factorial.lua") + testing.expectf(t, lua.Status(res) == .OK, "Expected L_dofile to return OKAY") + + fact := lua.L_checkinteger(state, -1) + + testing.expectf(t, fact == FACT_10, "Expected factorial(10) to return %v, got %v", FACT_10, fact) +} + +@(test) +// Test that our bindings didn't get out of sync with the API version +verify_lua_api_version :: proc(t: ^testing.T) { + state := lua.L_newstate() + defer lua.close(state) + + version := int(lua.version(state)) + + testing.expectf(t, version == lua.VERSION_NUM, "Expected lua.version to return %v, got %v", lua.VERSION_NUM, version) +} + +// Simple context.allocator-based callback for Lua. Use `lua.newstate` to pass the context as user data. +lua_context_allocator :: proc "c" (ud: rawptr, ptr: rawptr, osize, nsize: c.size_t) -> (buf: rawptr) { + old_size := int(osize) + new_size := int(nsize) + context = (^runtime.Context)(ud)^ + + if ptr == nil { + data, err := runtime.mem_alloc(new_size) + return raw_data(data) if err == .None else nil + } else { + if nsize > 0 { + data, err := runtime.mem_resize(ptr, old_size, new_size) + return raw_data(data) if err == .None else nil + } else { + runtime.mem_free(ptr) + return + } + } +} \ No newline at end of file diff --git a/vendor/lua/README.md b/vendor/lua/README.md index 8f4b0f5a5..4bc7804bb 100644 --- a/vendor/lua/README.md +++ b/vendor/lua/README.md @@ -1,12 +1,50 @@ # Lua in Odin -```odin -import lua "vendor:lua/5.4" // or whatever version you want -``` - Lua packages * `vendor:lua/5.1` (version 5.1.5) * `vendor:lua/5.2` (version 5.2.4) * `vendor:lua/5.3` (version 5.3.6) -* `vendor:lua/5.4` (version 5.4.2) \ No newline at end of file +* `vendor:lua/5.4` (version 5.4.2) + +With custom context-based allocator: + +```odin +package lua_example_with_context + +import "core:fmt" +import lua "vendor:lua/5.4" // or whatever version you want +import "core:c" +import "base:runtime" + +state: ^lua.State + +lua_allocator :: proc "c" (ud: rawptr, ptr: rawptr, osize, nsize: c.size_t) -> (buf: rawptr) { + old_size := int(osize) + new_size := int(nsize) + context = (^runtime.Context)(ud)^ + + if ptr == nil { + data, err := runtime.mem_alloc(new_size) + return raw_data(data) if err == .None else nil + } else { + if nsize > 0 { + data, err := runtime.mem_resize(ptr, old_size, new_size) + return raw_data(data) if err == .None else nil + } else { + runtime.mem_free(ptr) + return + } + } +} + +main :: proc() { + _context := context + state = lua.newstate(lua_allocator, &_context) + defer lua.close(state) + + lua.L_dostring(state, "return 'somestring'") + str := lua.tostring(state, -1) + fmt.println(str) +} +``` \ No newline at end of file From a055c03de9c1166c24559170b367f166c206faa3 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Mon, 22 Jul 2024 01:11:01 +0200 Subject: [PATCH 006/122] use #directory in lua test --- tests/vendor/lua/5.4/test_vendor_lua.5.4.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin b/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin index 5cfc2cefa..e331200ea 100644 --- a/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin +++ b/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin @@ -31,7 +31,7 @@ dofile_factorial :: proc(t: ^testing.T) { FACT_10 :: 3628800 - res := lua.L_dofile(state, "factorial.lua") + res := lua.L_dofile(state, #directory + "/factorial.lua") testing.expectf(t, lua.Status(res) == .OK, "Expected L_dofile to return OKAY") fact := lua.L_checkinteger(state, -1) From 4d86012d968925fcf8bcc263e4942781eab1cb31 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Mon, 22 Jul 2024 01:13:50 +0200 Subject: [PATCH 007/122] install lua for new lua vendor tests --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca3d87b12..84c85457f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,13 +91,13 @@ jobs: - name: Download LLVM (MacOS Intel) if: matrix.os == 'macos-13' run: | - brew install llvm@17 + brew install llvm@17 lua@5.4 echo "/usr/local/opt/llvm@17/bin" >> $GITHUB_PATH - name: Download LLVM (MacOS ARM) if: matrix.os == 'macos-14' run: | - brew install llvm@17 wasmtime + brew install llvm@17 wasmtime lua@5.4 echo "/opt/homebrew/opt/llvm@17/bin" >> $GITHUB_PATH - name: Build Odin From f3f08a4b47ecc2089be616eb9774ac3dd32e8a8d Mon Sep 17 00:00:00 2001 From: Emir Date: Tue, 23 Jul 2024 20:37:26 +0300 Subject: [PATCH 008/122] Add sdl2glue to `vendor:wgpu` package + triangle example --- .../wgpu/{example => examples/glfw}/Makefile | 6 +- .../wgpu/{example => examples/glfw}/build.bat | 4 +- .../wgpu/{example => examples/glfw}/main.odin | 0 .../{example => examples/glfw}/os_glfw.odin | 0 .../{example => examples/glfw}/os_js.odin | 0 .../{example => examples/glfw}/web/index.html | 0 vendor/wgpu/examples/sdl2/main.odin | 229 ++++++++++++++++++ vendor/wgpu/sdl2glue/glue.odin | 6 + vendor/wgpu/sdl2glue/glue_darwin.odin | 25 ++ vendor/wgpu/sdl2glue/glue_windows.odin | 25 ++ 10 files changed, 290 insertions(+), 5 deletions(-) rename vendor/wgpu/{example => examples/glfw}/Makefile (78%) rename vendor/wgpu/{example => examples/glfw}/build.bat (84%) rename vendor/wgpu/{example => examples/glfw}/main.odin (100%) rename vendor/wgpu/{example => examples/glfw}/os_glfw.odin (100%) rename vendor/wgpu/{example => examples/glfw}/os_js.odin (100%) rename vendor/wgpu/{example => examples/glfw}/web/index.html (100%) create mode 100644 vendor/wgpu/examples/sdl2/main.odin create mode 100644 vendor/wgpu/sdl2glue/glue.odin create mode 100644 vendor/wgpu/sdl2glue/glue_darwin.odin create mode 100644 vendor/wgpu/sdl2glue/glue_windows.odin diff --git a/vendor/wgpu/example/Makefile b/vendor/wgpu/examples/glfw/Makefile similarity index 78% rename from vendor/wgpu/example/Makefile rename to vendor/wgpu/examples/glfw/Makefile index f19997881..fdecdbb91 100644 --- a/vendor/wgpu/example/Makefile +++ b/vendor/wgpu/examples/glfw/Makefile @@ -8,10 +8,10 @@ PAGE_SIZE := 65536 INITIAL_MEMORY_BYTES := $(shell expr $(INITIAL_MEMORY_PAGES) \* $(PAGE_SIZE)) MAX_MEMORY_BYTES := $(shell expr $(MAX_MEMORY_PAGES) \* $(PAGE_SIZE)) -web/triangle.wasm: $(FILES) ../wgpu.js ../../wasm/js/runtime.js +web/triangle.wasm: $(FILES) ../../wgpu.js ../../../wasm/js/runtime.js odin build . \ -target:js_wasm32 -out:web/triangle.wasm -o:size \ -extra-linker-flags:"--export-table --import-memory --initial-memory=$(INITIAL_MEMORY_BYTES) --max-memory=$(MAX_MEMORY_BYTES)" - cp ../wgpu.js web/wgpu.js - cp ../../wasm/js/runtime.js web/runtime.js + cp ../../wgpu.js web/wgpu.js + cp ../../../wasm/js/runtime.js web/runtime.js diff --git a/vendor/wgpu/example/build.bat b/vendor/wgpu/examples/glfw/build.bat similarity index 84% rename from vendor/wgpu/example/build.bat rename to vendor/wgpu/examples/glfw/build.bat index cd3ca63ba..61afcbe66 100644 --- a/vendor/wgpu/example/build.bat +++ b/vendor/wgpu/examples/glfw/build.bat @@ -8,5 +8,5 @@ set /a MAX_MEMORY_BYTES=%MAX_MEMORY_PAGES% * %PAGE_SIZE% call odin.exe build . -target:js_wasm32 -out:web/triangle.wasm -o:size -extra-linker-flags:"--export-table --import-memory --initial-memory=%INITIAL_MEMORY_BYTES% --max-memory=%MAX_MEMORY_BYTES%" -copy "..\wgpu.js" "web\wgpu.js" -copy "..\..\wasm\js\runtime.js" "web\runtime.js" \ No newline at end of file +copy "..\..\wgpu.js" "web\wgpu.js" +copy "..\..\..\wasm\js\runtime.js" "web\runtime.js" \ No newline at end of file diff --git a/vendor/wgpu/example/main.odin b/vendor/wgpu/examples/glfw/main.odin similarity index 100% rename from vendor/wgpu/example/main.odin rename to vendor/wgpu/examples/glfw/main.odin diff --git a/vendor/wgpu/example/os_glfw.odin b/vendor/wgpu/examples/glfw/os_glfw.odin similarity index 100% rename from vendor/wgpu/example/os_glfw.odin rename to vendor/wgpu/examples/glfw/os_glfw.odin diff --git a/vendor/wgpu/example/os_js.odin b/vendor/wgpu/examples/glfw/os_js.odin similarity index 100% rename from vendor/wgpu/example/os_js.odin rename to vendor/wgpu/examples/glfw/os_js.odin diff --git a/vendor/wgpu/example/web/index.html b/vendor/wgpu/examples/glfw/web/index.html similarity index 100% rename from vendor/wgpu/example/web/index.html rename to vendor/wgpu/examples/glfw/web/index.html diff --git a/vendor/wgpu/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin new file mode 100644 index 000000000..80cdeb7bd --- /dev/null +++ b/vendor/wgpu/examples/sdl2/main.odin @@ -0,0 +1,229 @@ +package vendor_wgpu_example_triangle + +import "base:runtime" + +import "core:fmt" + +import "vendor:sdl2" +import "vendor:wgpu" +import "vendor:wgpu/sdl2glue" + +State :: struct { + ctx: runtime.Context, + window: ^sdl2.Window, + running: bool, + + instance: wgpu.Instance, + surface: wgpu.Surface, + adapter: wgpu.Adapter, + device: wgpu.Device, + config: wgpu.SurfaceConfiguration, + queue: wgpu.Queue, + module: wgpu.ShaderModule, + pipeline_layout: wgpu.PipelineLayout, + pipeline: wgpu.RenderPipeline, +} + +@(private="file") +state: State + +main :: proc() { + state.ctx = context + + sdl_flags := sdl2.InitFlags{.VIDEO, .JOYSTICK, .GAMECONTROLLER, .EVENTS} + if res := sdl2.Init(sdl_flags); res != 0 { + fmt.eprintf("ERROR: Failed to initialize SDL: [%s]\n", sdl2.GetError()) + return + } + + window_flags: sdl2.WindowFlags = {.SHOWN, .ALLOW_HIGHDPI, .RESIZABLE} + state.window = sdl2.CreateWindow( + "wgpu triangle", + sdl2.WINDOWPOS_CENTERED, + sdl2.WINDOWPOS_CENTERED, + 800, + 600, + window_flags, + ) + if state.window == nil { + fmt.eprintf("ERROR: Failed to create the SDL Window: [%s]\n", sdl2.GetError()) + return + } + + state.instance = wgpu.CreateInstance(nil) + if state.instance == nil { + panic("WebGPU is not supported") + } + + state.surface = sdl2glue.GetSurface(state.instance, state.window) + + wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, on_adapter, nil) + + on_adapter :: proc "c" (status: wgpu.RequestAdapterStatus, adapter: wgpu.Adapter, message: cstring, userdata: rawptr) { + context = state.ctx + if status != .Success || adapter == nil { + fmt.panicf("request adapter failure: [%v] %s", status, message) + } + state.adapter = adapter + wgpu.AdapterRequestDevice(adapter, nil, on_device) + } + + on_device :: proc "c" (status: wgpu.RequestDeviceStatus, device: wgpu.Device, message: cstring, userdata: rawptr) { + context = state.ctx + if status != .Success || device == nil { + fmt.panicf("request device failure: [%v] %s", status, message) + } + state.device = device + + width, height : u32 = 800, 600 // os_get_render_bounds(&state.os) + + state.config = wgpu.SurfaceConfiguration { + device = state.device, + usage = { .RenderAttachment }, + format = .BGRA8Unorm, + width = width, + height = height, + presentMode = .Fifo, + alphaMode = .Opaque, + } + wgpu.SurfaceConfigure(state.surface, &state.config) + + state.queue = wgpu.DeviceGetQueue(state.device) + + shader :: ` + @vertex + fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4 { + let x = f32(i32(in_vertex_index) - 1); + let y = f32(i32(in_vertex_index & 1u) * 2 - 1); + return vec4(x, y, 0.0, 1.0); + } + + @fragment + fn fs_main() -> @location(0) vec4 { + return vec4(1.0, 0.0, 0.0, 1.0); + }` + + state.module = wgpu.DeviceCreateShaderModule(state.device, &{ + nextInChain = &wgpu.ShaderModuleWGSLDescriptor{ + sType = .ShaderModuleWGSLDescriptor, + code = shader, + }, + }) + + state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(state.device, &{}) + state.pipeline = wgpu.DeviceCreateRenderPipeline(state.device, &{ + layout = state.pipeline_layout, + vertex = { + module = state.module, + entryPoint = "vs_main", + }, + fragment = &{ + module = state.module, + entryPoint = "fs_main", + targetCount = 1, + targets = &wgpu.ColorTargetState{ + format = .BGRA8Unorm, + writeMask = wgpu.ColorWriteMaskFlags_All, + }, + }, + primitive = { + topology = .TriangleList, + + }, + multisample = { + count = 1, + mask = 0xFFFFFFFF, + }, + }) + + now := sdl2.GetPerformanceCounter() + last : u64 = 0 + dt: f32 = 0 + main_loop: for { + last = now + now := sdl2.GetPerformanceCounter() + dt = auto_cast((now - last)*1000 / sdl2.GetPerformanceFrequency()) + + e: sdl2.Event + + for sdl2.PollEvent(&e) { + #partial switch (e.type) { + case .QUIT: + break main_loop + + case .WINDOWEVENT: + #partial switch (e.window.event) { + case .SIZE_CHANGED: + case .RESIZED: + state.config.width = cast(u32)e.window.data1 + state.config.height = cast(u32)e.window.data2 + wgpu.SurfaceConfigure(state.surface, &state.config) + } + } + } + + frame(dt) + } + } +} + +frame :: proc "c" (dt: f32) { + context = state.ctx + + surface_texture := wgpu.SurfaceGetCurrentTexture(state.surface) + switch surface_texture.status { + case .Success: + // All good, could check for `surface_texture.suboptimal` here. + case .Timeout, .Outdated, .Lost: + // Skip this frame, and re-configure surface. + if surface_texture.texture != nil { + wgpu.TextureRelease(surface_texture.texture) + } + // todo - resize() + return + case .OutOfMemory, .DeviceLost: + // Fatal error + fmt.panicf("[triangle] get_current_texture status=%v", surface_texture.status) + } + defer wgpu.TextureRelease(surface_texture.texture) + + frame := wgpu.TextureCreateView(surface_texture.texture, nil) + defer wgpu.TextureViewRelease(frame) + + command_encoder := wgpu.DeviceCreateCommandEncoder(state.device, nil) + defer wgpu.CommandEncoderRelease(command_encoder) + + render_pass_encoder := wgpu.CommandEncoderBeginRenderPass( + command_encoder, &{ + colorAttachmentCount = 1, + colorAttachments = &wgpu.RenderPassColorAttachment{ + view = frame, + loadOp = .Clear, + storeOp = .Store, + clearValue = { r = 0, g = 1, b = 0, a = 1 }, + }, + }, + ) + defer wgpu.RenderPassEncoderRelease(render_pass_encoder) + + wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline) + wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) + wgpu.RenderPassEncoderEnd(render_pass_encoder) + + command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil) + defer wgpu.CommandBufferRelease(command_buffer) + + wgpu.QueueSubmit(state.queue, { command_buffer }) + wgpu.SurfacePresent(state.surface) +} + +finish :: proc() { + wgpu.RenderPipelineRelease(state.pipeline) + wgpu.PipelineLayoutRelease(state.pipeline_layout) + wgpu.ShaderModuleRelease(state.module) + wgpu.QueueRelease(state.queue) + wgpu.DeviceRelease(state.device) + wgpu.AdapterRelease(state.adapter) + wgpu.SurfaceRelease(state.surface) + wgpu.InstanceRelease(state.instance) +} diff --git a/vendor/wgpu/sdl2glue/glue.odin b/vendor/wgpu/sdl2glue/glue.odin new file mode 100644 index 000000000..9da9a0738 --- /dev/null +++ b/vendor/wgpu/sdl2glue/glue.odin @@ -0,0 +1,6 @@ +//+build !linux +//+build !windows +//+build !darwin +package wgpu_sdl2_glue + +#panic("package wgpu/sdl2glue is not supported on the current target") diff --git a/vendor/wgpu/sdl2glue/glue_darwin.odin b/vendor/wgpu/sdl2glue/glue_darwin.odin new file mode 100644 index 000000000..6c962f714 --- /dev/null +++ b/vendor/wgpu/sdl2glue/glue_darwin.odin @@ -0,0 +1,25 @@ +package wgpu_sdl2_glue + +import "vendor:sdl2" +import "vendor:wgpu" +import CA "vendor:darwin/QuartzCore" +import NS "core:sys/darwin/Foundation" + +GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) + ns_window := cast(^NS.Window)window_info.info.cocoa.window + metal_layer := CA.MetalLayer_layer() + ns_window->contentView()->setLayer(metal_layer) + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromMetalLayer{ + chain = wgpu.ChainedStruct{ + sType = .SurfaceDescriptorFromMetalLayer, + }, + layer = rawptr(metal_layer), + }, + }, + ) +} \ No newline at end of file diff --git a/vendor/wgpu/sdl2glue/glue_windows.odin b/vendor/wgpu/sdl2glue/glue_windows.odin new file mode 100644 index 000000000..4bd30d452 --- /dev/null +++ b/vendor/wgpu/sdl2glue/glue_windows.odin @@ -0,0 +1,25 @@ +package wgpu_sdl2_glue + +import win "core:sys/windows" + +import "vendor:sdl2" +import "vendor:wgpu" + +GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) + hwnd := cast(win.HWND)window_info.info.win.window + hinstance := win.GetModuleHandleW(nil) + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromMetalLayer{ + chain = wgpu.ChainedStruct{ + sType = .SurfaceDescriptorFromMetalLayer, + }, + hinstance = rawptr(hinstance), + hwnd = rawptr(hwnd), + }, + }, + ) +} \ No newline at end of file From a4296031955c53d7d21b2dc14876384299978ec2 Mon Sep 17 00:00:00 2001 From: Emir Date: Tue, 23 Jul 2024 20:39:09 +0300 Subject: [PATCH 009/122] Remove unused variable from example --- vendor/wgpu/examples/sdl2/main.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/vendor/wgpu/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin index 80cdeb7bd..c593e7c2d 100644 --- a/vendor/wgpu/examples/sdl2/main.odin +++ b/vendor/wgpu/examples/sdl2/main.odin @@ -11,7 +11,6 @@ import "vendor:wgpu/sdl2glue" State :: struct { ctx: runtime.Context, window: ^sdl2.Window, - running: bool, instance: wgpu.Instance, surface: wgpu.Surface, From e8e51db9ff5534226c5e51d6518497d5ba55ecb0 Mon Sep 17 00:00:00 2001 From: Emir Date: Tue, 23 Jul 2024 20:42:26 +0300 Subject: [PATCH 010/122] Update glue.odin --- vendor/wgpu/sdl2glue/glue.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/vendor/wgpu/sdl2glue/glue.odin b/vendor/wgpu/sdl2glue/glue.odin index 9da9a0738..f4deb28dc 100644 --- a/vendor/wgpu/sdl2glue/glue.odin +++ b/vendor/wgpu/sdl2glue/glue.odin @@ -1,4 +1,3 @@ -//+build !linux //+build !windows //+build !darwin package wgpu_sdl2_glue From f9ef951b22b582af3fc5a228525ba546695a3d78 Mon Sep 17 00:00:00 2001 From: Emir Date: Tue, 23 Jul 2024 22:39:50 +0300 Subject: [PATCH 011/122] Add `sdl2glue/glue_linux.odin` --- vendor/wgpu/sdl2glue/glue.odin | 1 + vendor/wgpu/sdl2glue/glue_linux.odin | 42 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 vendor/wgpu/sdl2glue/glue_linux.odin diff --git a/vendor/wgpu/sdl2glue/glue.odin b/vendor/wgpu/sdl2glue/glue.odin index f4deb28dc..9da9a0738 100644 --- a/vendor/wgpu/sdl2glue/glue.odin +++ b/vendor/wgpu/sdl2glue/glue.odin @@ -1,3 +1,4 @@ +//+build !linux //+build !windows //+build !darwin package wgpu_sdl2_glue diff --git a/vendor/wgpu/sdl2glue/glue_linux.odin b/vendor/wgpu/sdl2glue/glue_linux.odin new file mode 100644 index 000000000..222a4ebc7 --- /dev/null +++ b/vendor/wgpu/sdl2glue/glue_linux.odin @@ -0,0 +1,42 @@ +package wgpu_sdl2_glue + +import "vendor:sdl2" +import "vendor:wgpu" + +GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) + if window_info.subsystem == .WAYLAND { + display := window_info.info.wl.display + surface := window_info.info.wl.surface + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromWaylandSurface{ + chain = { + sType = .SurfaceDescriptorFromWaylandSurface, + }, + display = display, + surface = surface, + }, + }, + ) + } else if window_info.subsystem == .X11 { + display := window_info.info.x11.display + window := window_info.info.x11.window + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromXlibWindow{ + chain = { + sType = .SurfaceDescriptorFromXlibWindow, + }, + display = display, + window = u64(window), + }, + }, + ) + } else { + panic("wgpu sdl2 glue: unsupported platform, expected Wayland or X11") + } +} From 2a2bedc85ca811641a0087545f65c56f27f43a53 Mon Sep 17 00:00:00 2001 From: Emir Date: Wed, 24 Jul 2024 10:22:18 +0300 Subject: [PATCH 012/122] Fix indentation and add full example --- vendor/wgpu/examples/sdl2/Makefile | 17 +++++ vendor/wgpu/examples/sdl2/build.bat | 12 ++++ vendor/wgpu/examples/sdl2/main.odin | 65 ++++-------------- vendor/wgpu/examples/sdl2/os_js.odin | 60 ++++++++++++++++ vendor/wgpu/examples/sdl2/os_sdl2.odin | 87 ++++++++++++++++++++++++ vendor/wgpu/examples/sdl2/web/index.html | 23 +++++++ vendor/wgpu/sdl2glue/glue_darwin.odin | 18 ++--- vendor/wgpu/sdl2glue/glue_linux.odin | 66 +++++++++--------- vendor/wgpu/sdl2glue/glue_windows.odin | 26 +++---- 9 files changed, 266 insertions(+), 108 deletions(-) create mode 100644 vendor/wgpu/examples/sdl2/Makefile create mode 100644 vendor/wgpu/examples/sdl2/build.bat create mode 100644 vendor/wgpu/examples/sdl2/os_js.odin create mode 100644 vendor/wgpu/examples/sdl2/os_sdl2.odin create mode 100644 vendor/wgpu/examples/sdl2/web/index.html diff --git a/vendor/wgpu/examples/sdl2/Makefile b/vendor/wgpu/examples/sdl2/Makefile new file mode 100644 index 000000000..fdecdbb91 --- /dev/null +++ b/vendor/wgpu/examples/sdl2/Makefile @@ -0,0 +1,17 @@ +FILES := $(wildcard *) + +# NOTE: changing this requires changing the same values in the `web/index.html`. +INITIAL_MEMORY_PAGES := 2000 +MAX_MEMORY_PAGES := 65536 + +PAGE_SIZE := 65536 +INITIAL_MEMORY_BYTES := $(shell expr $(INITIAL_MEMORY_PAGES) \* $(PAGE_SIZE)) +MAX_MEMORY_BYTES := $(shell expr $(MAX_MEMORY_PAGES) \* $(PAGE_SIZE)) + +web/triangle.wasm: $(FILES) ../../wgpu.js ../../../wasm/js/runtime.js + odin build . \ + -target:js_wasm32 -out:web/triangle.wasm -o:size \ + -extra-linker-flags:"--export-table --import-memory --initial-memory=$(INITIAL_MEMORY_BYTES) --max-memory=$(MAX_MEMORY_BYTES)" + + cp ../../wgpu.js web/wgpu.js + cp ../../../wasm/js/runtime.js web/runtime.js diff --git a/vendor/wgpu/examples/sdl2/build.bat b/vendor/wgpu/examples/sdl2/build.bat new file mode 100644 index 000000000..61afcbe66 --- /dev/null +++ b/vendor/wgpu/examples/sdl2/build.bat @@ -0,0 +1,12 @@ +REM NOTE: changing this requires changing the same values in the `web/index.html`. +set INITIAL_MEMORY_PAGES=2000 +set MAX_MEMORY_PAGES=65536 + +set PAGE_SIZE=65536 +set /a INITIAL_MEMORY_BYTES=%INITIAL_MEMORY_PAGES% * %PAGE_SIZE% +set /a MAX_MEMORY_BYTES=%MAX_MEMORY_PAGES% * %PAGE_SIZE% + +call odin.exe build . -target:js_wasm32 -out:web/triangle.wasm -o:size -extra-linker-flags:"--export-table --import-memory --initial-memory=%INITIAL_MEMORY_BYTES% --max-memory=%MAX_MEMORY_BYTES%" + +copy "..\..\wgpu.js" "web\wgpu.js" +copy "..\..\..\wasm\js\runtime.js" "web\runtime.js" \ No newline at end of file diff --git a/vendor/wgpu/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin index c593e7c2d..646f04c40 100644 --- a/vendor/wgpu/examples/sdl2/main.odin +++ b/vendor/wgpu/examples/sdl2/main.odin @@ -4,13 +4,11 @@ import "base:runtime" import "core:fmt" -import "vendor:sdl2" import "vendor:wgpu" -import "vendor:wgpu/sdl2glue" State :: struct { ctx: runtime.Context, - window: ^sdl2.Window, + os: OS, instance: wgpu.Instance, surface: wgpu.Surface, @@ -29,32 +27,13 @@ state: State main :: proc() { state.ctx = context - sdl_flags := sdl2.InitFlags{.VIDEO, .JOYSTICK, .GAMECONTROLLER, .EVENTS} - if res := sdl2.Init(sdl_flags); res != 0 { - fmt.eprintf("ERROR: Failed to initialize SDL: [%s]\n", sdl2.GetError()) - return - } - - window_flags: sdl2.WindowFlags = {.SHOWN, .ALLOW_HIGHDPI, .RESIZABLE} - state.window = sdl2.CreateWindow( - "wgpu triangle", - sdl2.WINDOWPOS_CENTERED, - sdl2.WINDOWPOS_CENTERED, - 800, - 600, - window_flags, - ) - if state.window == nil { - fmt.eprintf("ERROR: Failed to create the SDL Window: [%s]\n", sdl2.GetError()) - return - } + os_init(&state.os) state.instance = wgpu.CreateInstance(nil) if state.instance == nil { panic("WebGPU is not supported") } - - state.surface = sdl2glue.GetSurface(state.instance, state.window) + state.surface = os_get_surface(&state.os, state.instance) wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, on_adapter, nil) @@ -135,37 +114,17 @@ main :: proc() { }, }) - now := sdl2.GetPerformanceCounter() - last : u64 = 0 - dt: f32 = 0 - main_loop: for { - last = now - now := sdl2.GetPerformanceCounter() - dt = auto_cast((now - last)*1000 / sdl2.GetPerformanceFrequency()) - - e: sdl2.Event - - for sdl2.PollEvent(&e) { - #partial switch (e.type) { - case .QUIT: - break main_loop - - case .WINDOWEVENT: - #partial switch (e.window.event) { - case .SIZE_CHANGED: - case .RESIZED: - state.config.width = cast(u32)e.window.data1 - state.config.height = cast(u32)e.window.data2 - wgpu.SurfaceConfigure(state.surface, &state.config) - } - } - } - - frame(dt) - } + os_run(&state.os) } } +resize :: proc "c" () { + context = state.ctx + + state.config.width, state.config.height = os_get_render_bounds(&state.os) + wgpu.SurfaceConfigure(state.surface, &state.config) +} + frame :: proc "c" (dt: f32) { context = state.ctx @@ -178,7 +137,7 @@ frame :: proc "c" (dt: f32) { if surface_texture.texture != nil { wgpu.TextureRelease(surface_texture.texture) } - // todo - resize() + resize() return case .OutOfMemory, .DeviceLost: // Fatal error diff --git a/vendor/wgpu/examples/sdl2/os_js.odin b/vendor/wgpu/examples/sdl2/os_js.odin new file mode 100644 index 000000000..9634f4afe --- /dev/null +++ b/vendor/wgpu/examples/sdl2/os_js.odin @@ -0,0 +1,60 @@ +package vendor_wgpu_example_triangle + +import "vendor:wgpu" +import "vendor:wasm/js" + +OS :: struct { + initialized: bool, +} + +@(private="file") +g_os: ^OS + +os_init :: proc(os: ^OS) { + g_os = os + assert(js.add_window_event_listener(.Resize, nil, size_callback)) +} + +// NOTE: frame loop is done by the runtime.js repeatedly calling `step`. +os_run :: proc(os: ^OS) { + os.initialized = true +} + +os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) { + rect := js.get_bounding_client_rect("body") + return u32(rect.width), u32(rect.height) +} + +os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromCanvasHTMLSelector{ + sType = .SurfaceDescriptorFromCanvasHTMLSelector, + selector = "#wgpu-canvas", + }, + }, + ) +} + +@(private="file", export) +step :: proc(dt: f32) -> bool { + if !g_os.initialized { + return true + } + + frame(dt) + return true +} + +@(private="file", fini) +os_fini :: proc() { + js.remove_window_event_listener(.Resize, nil, size_callback) + + finish() +} + +@(private="file") +size_callback :: proc(e: js.Event) { + resize() +} diff --git a/vendor/wgpu/examples/sdl2/os_sdl2.odin b/vendor/wgpu/examples/sdl2/os_sdl2.odin new file mode 100644 index 000000000..bc48fd353 --- /dev/null +++ b/vendor/wgpu/examples/sdl2/os_sdl2.odin @@ -0,0 +1,87 @@ +//+build !js +package vendor_wgpu_example_triangle + +import "core:c" +import "core:fmt" + +import "vendor:sdl2" +import "vendor:wgpu" +import "vendor:wgpu/sdl2glue" + +OS :: struct { + window: ^sdl2.Window, +} + +os_init :: proc(os: ^OS) { + sdl_flags := sdl2.InitFlags{.VIDEO, .JOYSTICK, .GAMECONTROLLER, .EVENTS} + if res := sdl2.Init(sdl_flags); res != 0 { + fmt.eprintfln("ERROR: Failed to initialize SDL: [%s]", sdl2.GetError()) + return + } + + window_flags: sdl2.WindowFlags = {.SHOWN, .ALLOW_HIGHDPI, .RESIZABLE} + os.window = sdl2.CreateWindow( + "wgpu triangle", + sdl2.WINDOWPOS_CENTERED, + sdl2.WINDOWPOS_CENTERED, + 800, + 600, + window_flags, + ) + if os.window == nil { + fmt.eprintfln("ERROR: Failed to create the SDL Window: [%s]", sdl2.GetError()) + return + } + + sdl2.AddEventWatch(size_callback, nil) +} + +os_run :: proc(os: ^OS) { + now := sdl2.GetPerformanceCounter() + last : u64 + dt: f32 + main_loop: for { + last = now + now = sdl2.GetPerformanceCounter() + dt = f32((now - last) * 1000) / f32(sdl2.GetPerformanceFrequency()) + + e: sdl2.Event + + for sdl2.PollEvent(&e) { + #partial switch (e.type) { + case .QUIT: + break main_loop + } + } + + frame(dt) + } + + sdl2.DestroyWindow(os.window) + sdl2.Quit() + + finish() +} + + +os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) { + iw, ih: c.int + sdl2.GetWindowSize(os.window, &iw, &ih) + return u32(iw), u32(ih) +} + +os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { + return sdl2glue.GetSurface(instance, os.window) +} + +@(private="file") +size_callback :: proc "c" (userdata: rawptr, event: ^sdl2.Event) -> c.int { + + if event.type == .WINDOWEVENT { + if event.window.event == .SIZE_CHANGED || event.window.event == .RESIZED { + resize() + } + } + + return 0 +} diff --git a/vendor/wgpu/examples/sdl2/web/index.html b/vendor/wgpu/examples/sdl2/web/index.html new file mode 100644 index 000000000..61872e35a --- /dev/null +++ b/vendor/wgpu/examples/sdl2/web/index.html @@ -0,0 +1,23 @@ + + + + + + WGPU WASM Triangle + + + + + + + + + diff --git a/vendor/wgpu/sdl2glue/glue_darwin.odin b/vendor/wgpu/sdl2glue/glue_darwin.odin index 6c962f714..ba52f8824 100644 --- a/vendor/wgpu/sdl2glue/glue_darwin.odin +++ b/vendor/wgpu/sdl2glue/glue_darwin.odin @@ -6,14 +6,14 @@ import CA "vendor:darwin/QuartzCore" import NS "core:sys/darwin/Foundation" GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { - window_info: sdl2.SysWMinfo - sdl2.GetWindowWMInfo(window, &window_info) - ns_window := cast(^NS.Window)window_info.info.cocoa.window - metal_layer := CA.MetalLayer_layer() - ns_window->contentView()->setLayer(metal_layer) - return wgpu.InstanceCreateSurface( - instance, - &wgpu.SurfaceDescriptor{ + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) + ns_window := cast(^NS.Window)window_info.info.cocoa.window + metal_layer := CA.MetalLayer_layer() + ns_window->contentView()->setLayer(metal_layer) + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ nextInChain = &wgpu.SurfaceDescriptorFromMetalLayer{ chain = wgpu.ChainedStruct{ sType = .SurfaceDescriptorFromMetalLayer, @@ -21,5 +21,5 @@ GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surfac layer = rawptr(metal_layer), }, }, - ) + ) } \ No newline at end of file diff --git a/vendor/wgpu/sdl2glue/glue_linux.odin b/vendor/wgpu/sdl2glue/glue_linux.odin index 222a4ebc7..b01df251a 100644 --- a/vendor/wgpu/sdl2glue/glue_linux.odin +++ b/vendor/wgpu/sdl2glue/glue_linux.odin @@ -4,39 +4,39 @@ import "vendor:sdl2" import "vendor:wgpu" GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { - window_info: sdl2.SysWMinfo - sdl2.GetWindowWMInfo(window, &window_info) + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) if window_info.subsystem == .WAYLAND { - display := window_info.info.wl.display - surface := window_info.info.wl.surface - return wgpu.InstanceCreateSurface( - instance, - &wgpu.SurfaceDescriptor{ - nextInChain = &wgpu.SurfaceDescriptorFromWaylandSurface{ - chain = { - sType = .SurfaceDescriptorFromWaylandSurface, - }, - display = display, - surface = surface, - }, - }, - ) + display := window_info.info.wl.display + surface := window_info.info.wl.surface + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromWaylandSurface{ + chain = { + sType = .SurfaceDescriptorFromWaylandSurface, + }, + display = display, + surface = surface, + }, + }, + ) } else if window_info.subsystem == .X11 { - display := window_info.info.x11.display - window := window_info.info.x11.window - return wgpu.InstanceCreateSurface( - instance, - &wgpu.SurfaceDescriptor{ - nextInChain = &wgpu.SurfaceDescriptorFromXlibWindow{ - chain = { - sType = .SurfaceDescriptorFromXlibWindow, - }, - display = display, - window = u64(window), - }, - }, - ) - } else { - panic("wgpu sdl2 glue: unsupported platform, expected Wayland or X11") - } + display := window_info.info.x11.display + window := window_info.info.x11.window + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromXlibWindow{ + chain = { + sType = .SurfaceDescriptorFromXlibWindow, + }, + display = display, + window = u64(window), + }, + }, + ) + } else { + panic("wgpu sdl2 glue: unsupported platform, expected Wayland or X11") + } } diff --git a/vendor/wgpu/sdl2glue/glue_windows.odin b/vendor/wgpu/sdl2glue/glue_windows.odin index 4bd30d452..a2b1437ab 100644 --- a/vendor/wgpu/sdl2glue/glue_windows.odin +++ b/vendor/wgpu/sdl2glue/glue_windows.odin @@ -2,24 +2,24 @@ package wgpu_sdl2_glue import win "core:sys/windows" -import "vendor:sdl2" -import "vendor:wgpu" +import "vendor:sdl2" +import "vendor:wgpu" GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { - window_info: sdl2.SysWMinfo - sdl2.GetWindowWMInfo(window, &window_info) - hwnd := cast(win.HWND)window_info.info.win.window - hinstance := win.GetModuleHandleW(nil) - return wgpu.InstanceCreateSurface( - instance, - &wgpu.SurfaceDescriptor{ - nextInChain = &wgpu.SurfaceDescriptorFromMetalLayer{ + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) + hwnd := window_info.info.win.window + hinstance := win.GetModuleHandleW(nil) + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromWindowsHWND{ chain = wgpu.ChainedStruct{ - sType = .SurfaceDescriptorFromMetalLayer, + sType = .SurfaceDescriptorFromWindowsHWND, }, hinstance = rawptr(hinstance), hwnd = rawptr(hwnd), }, }, - ) -} \ No newline at end of file + ) +} From 95412df129fa3c6b19d5597b0aee78afcaa32340 Mon Sep 17 00:00:00 2001 From: Emir Date: Wed, 24 Jul 2024 10:27:00 +0300 Subject: [PATCH 013/122] Add newline to glue_darwin.odin --- vendor/wgpu/sdl2glue/glue_darwin.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/wgpu/sdl2glue/glue_darwin.odin b/vendor/wgpu/sdl2glue/glue_darwin.odin index ba52f8824..c48b8488c 100644 --- a/vendor/wgpu/sdl2glue/glue_darwin.odin +++ b/vendor/wgpu/sdl2glue/glue_darwin.odin @@ -22,4 +22,4 @@ GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surfac }, }, ) -} \ No newline at end of file +} From 57dc6c2e94473ec45ad6a8980e359fcd9cb8c409 Mon Sep 17 00:00:00 2001 From: Emir Date: Wed, 24 Jul 2024 10:27:22 +0300 Subject: [PATCH 014/122] Update os_sdl2.odin --- vendor/wgpu/examples/sdl2/os_sdl2.odin | 2 -- 1 file changed, 2 deletions(-) diff --git a/vendor/wgpu/examples/sdl2/os_sdl2.odin b/vendor/wgpu/examples/sdl2/os_sdl2.odin index bc48fd353..bbcec9923 100644 --- a/vendor/wgpu/examples/sdl2/os_sdl2.odin +++ b/vendor/wgpu/examples/sdl2/os_sdl2.odin @@ -76,12 +76,10 @@ os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { @(private="file") size_callback :: proc "c" (userdata: rawptr, event: ^sdl2.Event) -> c.int { - if event.type == .WINDOWEVENT { if event.window.event == .SIZE_CHANGED || event.window.event == .RESIZED { resize() } } - return 0 } From ba81a81ca8ada09a896a1a8fa3818d8b0c09be62 Mon Sep 17 00:00:00 2001 From: Emir Date: Wed, 24 Jul 2024 10:29:34 +0300 Subject: [PATCH 015/122] Update os_sdl2.odin --- vendor/wgpu/examples/sdl2/os_sdl2.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/wgpu/examples/sdl2/os_sdl2.odin b/vendor/wgpu/examples/sdl2/os_sdl2.odin index bbcec9923..0e6c5b57a 100644 --- a/vendor/wgpu/examples/sdl2/os_sdl2.odin +++ b/vendor/wgpu/examples/sdl2/os_sdl2.odin @@ -21,11 +21,11 @@ os_init :: proc(os: ^OS) { window_flags: sdl2.WindowFlags = {.SHOWN, .ALLOW_HIGHDPI, .RESIZABLE} os.window = sdl2.CreateWindow( - "wgpu triangle", + "WGPU Native Triangle", sdl2.WINDOWPOS_CENTERED, sdl2.WINDOWPOS_CENTERED, - 800, - 600, + 960, + 540, window_flags, ) if os.window == nil { From c98bb7da39b2acdfe1dc5a3426102ed27944b358 Mon Sep 17 00:00:00 2001 From: Emir Date: Wed, 24 Jul 2024 10:33:34 +0300 Subject: [PATCH 016/122] Update README.md --- vendor/wgpu/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/vendor/wgpu/README.md b/vendor/wgpu/README.md index 59b31567f..8b2c95b5e 100644 --- a/vendor/wgpu/README.md +++ b/vendor/wgpu/README.md @@ -37,13 +37,20 @@ The bindings work on both `-target:js_wasm32` and `-target:js_wasm64p32`. ## GLFW Glue There is an inner package `glfwglue` that can be used to glue together WGPU and GLFW. -It exports one procedure `GetSurface(wgpu.Instance, glfw.WindowHandle) -> glfw.Surface`. +It exports one procedure `GetSurface(wgpu.Instance, glfw.WindowHandle) -> wgpu.Surface`. The procedure will call the needed target specific procedures and return a surface configured for the given window. Do note that wgpu does not require GLFW, you can use native windows or another windowing library too. For that you can take inspiration from `glfwglue` on glueing them together. +## SDL2 Glue + +There is an inner package `sdl2glue` that can be used to glue together WGPU and SDL2. +It exports one procedure `GetSurface(wgpu.Instance, ^sdl2.Window) -> wgpu.Surface`. +The procedure will call the needed target specific procedures and return a surface configured +for the given window. + ### Wayland GLFW supports Wayland from version 3.4 onwards and only if it is compiled with `-DGLFW_EXPOSE_NATIVE_WAYLAND`. From 8d6ff5192228c9225e66c650f83bb7c2da005ab2 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 24 Jul 2024 17:43:51 +0200 Subject: [PATCH 017/122] Copy lua54.dll during CI test --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84c85457f..977468f5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -207,6 +207,7 @@ jobs: shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + copy vendor\lua\5.4\windows\*.dll . odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false - name: Odin internals tests shell: cmd From f03c2b7783518f05f7804dfe51adaef4b5e5020e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Jul 2024 21:45:35 +0100 Subject: [PATCH 018/122] General clean up of `os2.read_directory` for Windows --- core/os/os2/dir_windows.odin | 15 ++++++++++++++- core/os/os2/file_windows.odin | 28 ++++++++++++++++++---------- core/os/os2/path_windows.odin | 11 ++++++----- core/os/os2/stat.odin | 4 ++-- core/os/os2/stat_windows.odin | 3 ++- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/core/os/os2/dir_windows.odin b/core/os/os2/dir_windows.odin index c767bd3b9..84f320095 100644 --- a/core/os/os2/dir_windows.odin +++ b/core/os/os2/dir_windows.odin @@ -23,10 +23,21 @@ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, al fi.type, fi.mode = _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, d.dwReserved0) - // fi.inode = u128(u64(d.nFileIndexHigh)<<32 + u64(d.nFileIndexLow)) fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime)) fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime)) fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime)) + + + handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0) + defer win32.CloseHandle(handle) + + if file_id_info: win32.FILE_ID_INFO; handle != nil && win32.GetFileInformationByHandleEx(handle, .FileIdInfo, &file_id_info, size_of(file_id_info)) { + #assert(size_of(fi.inode) == size_of(file_id_info.FileId)) + #assert(size_of(fi.inode) == 16) + runtime.mem_copy_non_overlapping(&fi.inode, &file_id_info.FileId, 16) + } + + return } @@ -46,6 +57,8 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info return } + TEMP_ALLOCATOR_GUARD() + for !it.impl.no_more_files { err: Error file_info_delete(it.impl.prev_fi, file_allocator()) diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index 55365c1bd..48a5427f1 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -60,8 +60,9 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u err = .Not_Exist return } + TEMP_ALLOCATOR_GUARD() - path := _fix_long_path(name) or_return + path := _fix_long_path(name, temp_allocator()) or_return access: u32 switch flags & {.Read, .Write} { case {.Read}: access = win32.FILE_GENERIC_READ @@ -457,7 +458,8 @@ _truncate :: proc(f: ^File, size: i64) -> Error { } _remove :: proc(name: string) -> Error { - p := _fix_long_path(name) or_return + TEMP_ALLOCATOR_GUARD() + p := _fix_long_path(name, temp_allocator()) or_return err, err1: Error if !win32.DeleteFileW(p) { err = _get_platform_error() @@ -494,8 +496,9 @@ _remove :: proc(name: string) -> Error { } _rename :: proc(old_path, new_path: string) -> Error { - from := _fix_long_path(old_path) or_return - to := _fix_long_path(new_path) or_return + TEMP_ALLOCATOR_GUARD() + from := _fix_long_path(old_path, temp_allocator()) or_return + to := _fix_long_path(new_path, temp_allocator()) or_return if win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) { return nil } @@ -504,8 +507,9 @@ _rename :: proc(old_path, new_path: string) -> Error { } _link :: proc(old_name, new_name: string) -> Error { - o := _fix_long_path(old_name) or_return - n := _fix_long_path(new_name) or_return + TEMP_ALLOCATOR_GUARD() + o := _fix_long_path(old_name, temp_allocator()) or_return + n := _fix_long_path(new_name, temp_allocator()) or_return if win32.CreateHardLinkW(n, o, nil) { return nil } @@ -592,8 +596,10 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er @thread_local rdb_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]byte - p := _fix_long_path(name) or_return - handle := _open_sym_link(p) or_return + TEMP_ALLOCATOR_GUARD() + + p := _fix_long_path(name, temp_allocator()) or_return + handle := _open_sym_link(p) or_return defer win32.CloseHandle(handle) bytes_returned: u32 @@ -667,7 +673,8 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error { } _chdir :: proc(name: string) -> Error { - p := _fix_long_path(name) or_return + TEMP_ALLOCATOR_GUARD() + p := _fix_long_path(name, temp_allocator()) or_return if !win32.SetCurrentDirectoryW(p) { return _get_platform_error() } @@ -723,7 +730,8 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error { } _exists :: proc(path: string) -> bool { - wpath, _ := _fix_long_path(path) + TEMP_ALLOCATOR_GUARD() + wpath, _ := _fix_long_path(path, temp_allocator()) attribs := win32.GetFileAttributesW(wpath) return attribs != win32.INVALID_FILE_ATTRIBUTES } diff --git a/core/os/os2/path_windows.odin b/core/os/os2/path_windows.odin index c93c929f2..4aa695ee2 100644 --- a/core/os/os2/path_windows.odin +++ b/core/os/os2/path_windows.odin @@ -13,7 +13,8 @@ _is_path_separator :: proc(c: byte) -> bool { } _mkdir :: proc(name: string, perm: int) -> Error { - if !win32.CreateDirectoryW(_fix_long_path(name) or_return, nil) { + TEMP_ALLOCATOR_GUARD() + if !win32.CreateDirectoryW(_fix_long_path(name, temp_allocator()) or_return, nil) { return _get_platform_error() } return nil @@ -169,13 +170,13 @@ init_long_path_support :: proc() { } @(require_results) -_fix_long_path_slice :: proc(path: string) -> ([]u16, runtime.Allocator_Error) { - return win32_utf8_to_utf16(_fix_long_path_internal(path), temp_allocator()) +_fix_long_path_slice :: proc(path: string, allocator: runtime.Allocator) -> ([]u16, runtime.Allocator_Error) { + return win32_utf8_to_utf16(_fix_long_path_internal(path), allocator) } @(require_results) -_fix_long_path :: proc(path: string) -> (win32.wstring, runtime.Allocator_Error) { - return win32_utf8_to_wstring(_fix_long_path_internal(path), temp_allocator()) +_fix_long_path :: proc(path: string, allocator: runtime.Allocator) -> (win32.wstring, runtime.Allocator_Error) { + return win32_utf8_to_wstring(_fix_long_path_internal(path), allocator) } @(require_results) diff --git a/core/os/os2/stat.odin b/core/os/os2/stat.odin index 5c063e771..b3ca47be3 100644 --- a/core/os/os2/stat.odin +++ b/core/os/os2/stat.odin @@ -12,8 +12,8 @@ File_Info :: struct { name: string, inode: u128, // might be zero if cannot be determined - size: i64, - mode: int, + size: i64 `fmt:"M"`, + mode: int `fmt:"o"`, type: File_Type, creation_time: time.Time, diff --git a/core/os/os2/stat_windows.odin b/core/os/os2/stat_windows.odin index 4d67ddb58..3a3a3b1b4 100644 --- a/core/os/os2/stat_windows.odin +++ b/core/os/os2/stat_windows.odin @@ -67,8 +67,9 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runt if len(name) == 0 { return {}, .Not_Exist } + TEMP_ALLOCATOR_GUARD() - wname := _fix_long_path(name) or_return + wname := _fix_long_path(name, temp_allocator()) or_return fa: win32.WIN32_FILE_ATTRIBUTE_DATA ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa) if ok && fa.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { From 4ff62994bfb41f2ca32c0dbb9c6e0d083e716dae Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 24 Jul 2024 22:54:17 +0200 Subject: [PATCH 019/122] Add CLSCTX_ALL --- core/sys/windows/types.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 557fb5a58..0762ec76c 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -2453,6 +2453,7 @@ CLSCTX_RESERVED6 :: 0x1000000 CLSCTX_ACTIVATE_ARM32_SERVER :: 0x2000000 CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION :: 0x4000000 CLSCTX_PS_DLL :: 0x80000000 +CLSCTX_ALL :: CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER WSAPROTOCOLCHAIN :: struct { ChainLen: c_int, From 85880f9defc4d33482c1737ceffc4aed74b37177 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Jul 2024 21:55:51 +0100 Subject: [PATCH 020/122] Add more NtDll stuff --- core/sys/windows/ntdll.odin | 38 +++++++++++++++++++++++++++++++++++++ core/sys/windows/types.odin | 1 + 2 files changed, 39 insertions(+) diff --git a/core/sys/windows/ntdll.odin b/core/sys/windows/ntdll.odin index 20c75c801..23444ff34 100644 --- a/core/sys/windows/ntdll.odin +++ b/core/sys/windows/ntdll.odin @@ -23,8 +23,24 @@ foreign ntdll_lib { Length: ULONG, FileInformationClass: FILE_INFORMATION_CLASS, ) -> NTSTATUS --- + + NtQueryDirectoryFileEx :: proc( + FileHandle: HANDLE, + Event: HANDLE, + ApcRoutine: PIO_APC_ROUTINE, + ApcContext: PVOID, + IoStatusBlock: PIO_STATUS_BLOCK, + FileInformation: PVOID, + Length: ULONG, + FileInformationClass: FILE_INFORMATION_CLASS, + QueryFlags: ULONG, + FileName : PUNICODE_STRING, + ) -> NTSTATUS --- } + +PIO_APC_ROUTINE :: #type proc "system" (ApcContext: rawptr, IoStatusBlock: PIO_STATUS_BLOCK, Reserved: ULONG) + PIO_STATUS_BLOCK :: ^IO_STATUS_BLOCK IO_STATUS_BLOCK :: struct { using _: struct #raw_union { @@ -45,6 +61,12 @@ PROCESS_INFO_CLASS :: enum c_int { ProcessSubsystemInformation = 75, } +SL_RESTART_SCAN :: 0x00000001 // The scan will start at the first entry in the directory. If this flag is not set, the scan will resume from where the last query ended. +SL_RETURN_SINGLE_ENTRY :: 0x00000002 // Normally the return buffer is packed with as many matching directory entries that fit. If this flag is set, the file system will return only one directory entry at a time. This does make the operation less efficient. +SL_INDEX_SPECIFIED :: 0x00000004 // The scan should start at a specified indexed position in the directory. This flag can only be set if you generate your own IRP_MJ_DIRECTORY_CONTROL IRP; the index is specified in the IRP. How the position is specified varies from file system to file system. +SL_RETURN_ON_DISK_ENTRIES_ONLY :: 0x00000008 // Any file system filters that perform directory virtualization or just-in-time expansion should simply pass the request through to the file system and return entries that are currently on disk. Not all file systems support this flag. +SL_NO_CURSOR_UPDATE_QUERY :: 0x00000010 // File systems maintain per-FileObject directory cursor information. When multiple threads do queries using the same FileObject, access to the per-FileObject structure is single threaded to prevent corruption of the cursor state. This flag tells the file system to not update per-FileObject cursor state information thus allowing multiple threads to query in parallel using the same handle. It behaves as if SL_RESTART_SCAN is specified on each call. If a wild card pattern is given on the next call, the operation will not pick up where the last query ended. This allows for true asynchronous directory query support. If this flag is used inside a TxF transaction the operation will be failed. Not all file systems support this flag. + PFILE_INFORMATION_CLASS :: ^FILE_INFORMATION_CLASS FILE_INFORMATION_CLASS :: enum c_int { @@ -134,6 +156,22 @@ FILE_INFORMATION_CLASS :: enum c_int { FileMaximumInformation, } +PFILE_ID_FULL_DIR_INFORMATION :: ^FILE_ID_FULL_DIR_INFORMATION +FILE_ID_FULL_DIR_INFORMATION :: struct { + NextEntryOffset: ULONG, + FileIndex: ULONG, + CreationTime: LARGE_INTEGER, + LastAccessTime: LARGE_INTEGER, + LastWriteTime: LARGE_INTEGER, + ChangeTime: LARGE_INTEGER, + EndOfFile: LARGE_INTEGER, + AllocationSize: LARGE_INTEGER, + FileAttributes: ULONG, + FileNameLength: ULONG, + EaSize: ULONG, + FileId: LARGE_INTEGER, + FileName: [1]WCHAR, +} PROCESS_BASIC_INFORMATION :: struct { diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 557fb5a58..55520d5ad 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -2512,6 +2512,7 @@ OBJECT_ATTRIBUTES :: struct { SecurityQualityOfService: rawptr, } +PUNICODE_STRING :: ^UNICODE_STRING UNICODE_STRING :: struct { Length: u16 `fmt:"-"`, MaximumLength: u16 `fmt:"-"`, From fe4754a77c9aa36e2b705b22e89bb1952fb05565 Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Thu, 25 Jul 2024 10:27:49 +0200 Subject: [PATCH 021/122] format --- core/sys/windows/gdi32.odin | 4 ++-- core/sys/windows/user32.odin | 38 ++++++++++++++++++------------------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index 6c7eda03d..6788ed2ea 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -23,8 +23,8 @@ foreign gdi32 { CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH --- CreateDIBitmap :: proc(hdc: HDC, pbmih: ^BITMAPINFOHEADER, flInit: DWORD, pjBits: VOID, pbmi: ^BITMAPINFO, iUsage: UINT) -> HBITMAP --- CreateDIBSection :: proc(hdc: HDC, pbmi: ^BITMAPINFO, usage: UINT, ppvBits: VOID, hSection: HANDLE, offset: DWORD) -> HBITMAP --- - StretchDIBits :: proc(hdc: HDC, xDest: INT, yDest: INT, DestWidth: INT, DestHeight: INT, xSrc: INT, ySrc: INT, SrcWidth: INT, SrcHeight: INT, lpBits: VOID, lpbmi: ^BITMAPINFO, iUsage: UINT, rop: DWORD) -> INT --- - StretchBlt :: proc(hdcDest: HDC, xDest: INT, yDest: INT, wDest: INT, hDest: INT, hdcSrc: HDC, xSrc: INT, ySrc: INT, wSrc: INT, hSrc: INT, rop: DWORD) -> BOOL --- + StretchDIBits :: proc(hdc: HDC, xDest, yDest, DestWidth, DestHeight, xSrc, ySrc, SrcWidth, SrcHeight: INT, lpBits: VOID, lpbmi: ^BITMAPINFO, iUsage: UINT, rop: DWORD) -> INT --- + StretchBlt :: proc(hdcDest: HDC, xDest, yDest, wDest, hDest: INT, hdcSrc: HDC, xSrc, ySrc, wSrc, hSrc: INT, rop: DWORD) -> BOOL --- SetPixelFormat :: proc(hdc: HDC, format: INT, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL --- ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> INT --- diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 96ccb7dda..656da86ed 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -570,7 +570,7 @@ WINDOWINFO :: struct { PWINDOWINFO :: ^WINDOWINFO DRAWTEXTPARAMS :: struct { - cbSize : UINT, + cbSize: UINT, iTabLength: INT, iLeftMargin: INT, iRightMargin: INT, @@ -631,9 +631,9 @@ GetUserObjectInformationFlags :: enum INT { } USEROBJECTFLAGS :: struct { - fInherit: BOOL, - fReserved: BOOL, - dwFlags: DWORD, + fInherit: BOOL, + fReserved: BOOL, + dwFlags: DWORD, } PROPENUMPROCW :: #type proc(unnamedParam1: HWND, unnamedParam2: LPCWSTR, unnamedParam3: HANDLE) -> BOOL @@ -688,18 +688,18 @@ MIIM_BITMAP :: 0x00000080 MIIM_FTYPE :: 0x00000100 MENUITEMINFOW :: struct { - cbSize: UINT, - fMask: UINT, - fType: UINT, // used if MIIM_TYPE (4.0) or MIIM_FTYPE (>4.0) - fState: UINT, // used if MIIM_STATE - wID: UINT, // used if MIIM_ID - hSubMenu: HMENU, // used if MIIM_SUBMENU - hbmpChecked: HBITMAP, // used if MIIM_CHECKMARKS - hbmpUnchecked: HBITMAP, // used if MIIM_CHECKMARKS - dwItemData: ULONG_PTR, // used if MIIM_DATA - dwTypeData: LPWSTR, // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0) - cch: UINT, // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0) - hbmpItem: HBITMAP, // used if MIIM_BITMAP + cbSize: UINT, + fMask: UINT, + fType: UINT, // used if MIIM_TYPE (4.0) or MIIM_FTYPE (>4.0) + fState: UINT, // used if MIIM_STATE + wID: UINT, // used if MIIM_ID + hSubMenu: HMENU, // used if MIIM_SUBMENU + hbmpChecked: HBITMAP, // used if MIIM_CHECKMARKS + hbmpUnchecked: HBITMAP, // used if MIIM_CHECKMARKS + dwItemData: ULONG_PTR, // used if MIIM_DATA + dwTypeData: LPWSTR, // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0) + cch: UINT, // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0) + hbmpItem: HBITMAP, // used if MIIM_BITMAP } LPMENUITEMINFOW :: ^MENUITEMINFOW DISPLAY_DEVICEW :: struct { @@ -716,7 +716,7 @@ PDISPLAY_DEVICEW :: ^DISPLAY_DEVICEW WinEventFlags :: bit_set[WinEventFlag; DWORD] WinEventFlag :: enum DWORD { - SKIPOWNTHREAD = 0, - SKIPOWNPROCESS = 1, - INCONTEXT = 2, + SKIPOWNTHREAD = 0, + SKIPOWNPROCESS = 1, + INCONTEXT = 2, } From 9088a493d9e090f7a44d1491a9072c25ff07a7b7 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 25 Jul 2024 19:43:42 +0200 Subject: [PATCH 022/122] Add `time.to_string*` formatters. --- core/time/time.odin | 336 ++++++++++++++++++++++++++++ tests/core/time/test_core_time.odin | 37 +++ 2 files changed, 373 insertions(+) diff --git a/core/time/time.odin b/core/time/time.odin index fad6512f3..131629dcb 100644 --- a/core/time/time.odin +++ b/core/time/time.odin @@ -389,6 +389,342 @@ clock_from_seconds :: proc "contextless" (nsec: u64) -> (hour, min, sec: int) { return } +/* +Formats a `Time` as a 24-hour `HH:MM:SS` string. + +**Inputs**: +- `t`: The `Time` to format. +- `buf`: The backing buffer to use. + +**Returns**: +- The formatted string `res`, backed by `buf`. + +**Example**: + +In order to format the current time, the following code can be used: + +```odin +buf: [8]u8 +now := time.now() +fmt.println(time.to_string_hms(now, buf[:])) +``` +*/ +time_to_string_hms :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { + assert(len(buf) >= 8) + h, m, s := clock(t) + + buf[7] = '0' + u8(s % 10); s /= 10 + buf[6] = '0' + u8(s) + buf[5] = ':' + buf[4] = '0' + u8(m % 10); m /= 10 + buf[3] = '0' + u8(m) + buf[2] = ':' + buf[1] = '0' + u8(h % 10); h /= 10 + buf[0] = '0' + u8(h) + + return string(buf[:8]) +} + +/* +Formats a `Duration` as a 24-hour `HH:MM:SS` string. + +**Inputs**: +- `d`: The `Duration` to format. +- `buf`: The backing buffer to use. + +**Returns**: +- The formatted string `res`, backed by `buf`. + +**Example**: + +In order to format a duration, the following code can be used: + +```odin +buf: [8]u8 +d := time.since(earlier) +fmt.println(time.to_string_hms(d, buf[:])) +``` +*/ +duration_to_string_hms :: proc(d: Duration, buf: []u8) -> (res: string) #no_bounds_check { + return time_to_string_hms(Time{_nsec=i64(d)}, buf) +} + +to_string_hms :: proc{time_to_string_hms, duration_to_string_hms} + + +/* +Formats a `Time` as a 12-hour `HH:MM:SS pm` string. + +**Inputs**: +- `t`: The `Time` to format. +- `buf`: The backing buffer to use. +- `ampm`: An optional pair of AM/PM strings to use in place of the default. + +**Returns**: +- The formatted string `res`, backed by `buf`. + +**Example**: + +In order to format the current time, the following code can be used: + +```odin +buf: [64]u8 +now := time.now() +fmt.println(time.to_string_hms_12(now, buf[:])) +fmt.println(time.to_string_hms_12(now, buf[:], {"㏂", "㏘"})) +``` +*/ +to_string_hms_12 :: proc(t: Time, buf: []u8, ampm: [2]string = {" am", " pm"}) -> (res: string) #no_bounds_check { + assert(len(buf) >= 8 + max(len(ampm[0]), len(ampm[1]))) + h, m, s := clock(t) + + _h := h % 12 + buf[7] = '0' + u8(s % 10); s /= 10 + buf[6] = '0' + u8(s) + buf[5] = ':' + buf[4] = '0' + u8(m % 10); m /= 10 + buf[3] = '0' + u8(m) + buf[2] = ':' + buf[1] = '0' + u8(_h% 10); _h /= 10 + buf[0] = '0' + u8(_h) + + if h < 13 { + copy(buf[8:], ampm[0]) + return string(buf[:8+len(ampm[0])]) + } else { + copy(buf[8:], ampm[1]) + return string(buf[:8+len(ampm[1])]) + } +} + +/* +Formats a `Time` as a `yyyy-mm-dd` date string. + +**Inputs**: +- `t`: The `Time` to format. +- `buf`: The backing buffer to use. + +**Returns**: +- The formatted string `res`, backed by `buf`. + +**Example**: + +In order to format the current date, the following code can be used: + +```odin +buf: [10]u8 +now := time.now() +fmt.println(time.to_string_yyyy_mm_dd(now, buf[:])) +``` +*/ +to_string_yyyy_mm_dd :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { + assert(len(buf) >= 10) + y, _m, d := date(t) + m := u8(_m) + + buf[9] = '0' + u8(d % 10); d /= 10 + buf[8] = '0' + u8(d % 10) + buf[7] = '-' + buf[6] = '0' + u8(m % 10); m /= 10 + buf[5] = '0' + u8(m % 10) + buf[4] = '-' + buf[3] = '0' + u8(y % 10); y /= 10 + buf[2] = '0' + u8(y % 10); y /= 10 + buf[1] = '0' + u8(y % 10); y /= 10 + buf[0] = '0' + u8(y) + + return string(buf[:10]) +} + +/* +Formats a `Time` as a `yy-mm-dd` date string. + +**Inputs**: +- `t`: The `Time` to format. +- `buf`: The backing buffer to use. + +**Returns**: +- The formatted string `res`, backed by `buf`. + +**Example**: + +In order to format the current date, the following code can be used: + +```odin +buf: [8]u8 +now := time.now() +fmt.println(time.to_string_yy_mm_dd(now, buf[:])) +``` +*/ +to_string_yy_mm_dd :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { + assert(len(buf) >= 8) + y, _m, d := date(t) + y %= 100; m := u8(_m) + + buf[7] = '0' + u8(d % 10); d /= 10 + buf[6] = '0' + u8(d % 10) + buf[5] = '-' + buf[4] = '0' + u8(m % 10); m /= 10 + buf[3] = '0' + u8(m % 10) + buf[2] = '-' + buf[1] = '0' + u8(y % 10); y /= 10 + buf[0] = '0' + u8(y) + + return string(buf[:8]) +} + +/* +Formats a `Time` as a `dd-mm-yyyy` date string. + +**Inputs**: +- `t`: The `Time` to format. +- `buf`: The backing buffer to use. + +**Returns**: +- The formatted string `res`, backed by `buf`. + +**Example**: + +In order to format the current date, the following code can be used: + +```odin +buf: [10]u8 +now := time.now() +fmt.println(time.to_string_dd_mm_yyyy(now, buf[:])) +``` +*/ +to_string_dd_mm_yyyy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { + assert(len(buf) >= 10) + y, _m, d := date(t) + m := u8(_m) + + buf[9] = '0' + u8(y % 10); y /= 10 + buf[8] = '0' + u8(y % 10); y /= 10 + buf[7] = '0' + u8(y % 10); y /= 10 + buf[6] = '0' + u8(y) + buf[5] = '-' + buf[4] = '0' + u8(m % 10); m /= 10 + buf[3] = '0' + u8(m % 10) + buf[2] = '-' + buf[1] = '0' + u8(d % 10); d /= 10 + buf[0] = '0' + u8(d % 10) + + return string(buf[:10]) +} + +/* +Formats a `Time` as a `dd-mm-yy` date string. + +**Inputs**: +- `t`: The `Time` to format. +- `buf`: The backing buffer to use. + +**Returns**: +- The formatted string `res`, backed by `buf`. + +**Example**: + +In order to format the current date, the following code can be used: + +```odin +buf: [8]u8 +now := time.now() +fmt.println(time.to_string_dd_mm_yy(now, buf[:])) +``` +*/ +to_string_dd_mm_yy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { + assert(len(buf) >= 8) + y, _m, d := date(t) + y %= 100; m := u8(_m) + + buf[7] = '0' + u8(y % 10); y /= 10 + buf[6] = '0' + u8(y) + buf[5] = '-' + buf[4] = '0' + u8(m % 10); m /= 10 + buf[3] = '0' + u8(m % 10) + buf[2] = '-' + buf[1] = '0' + u8(d % 10); d /= 10 + buf[0] = '0' + u8(d % 10) + + return string(buf[:8]) +} + +/* +Formats a `Time` as a `mm-dd-yyyy` date string. + +**Inputs**: +- `t`: The `Time` to format. +- `buf`: The backing buffer to use. + +**Returns**: +- The formatted string `res`, backed by `buf`. + +**Example**: + +In order to format the current date, the following code can be used: + +```odin +buf: [10]u8 +now := time.now() +fmt.println(time.to_string_mm_dd_yyyy(now, buf[:])) +``` +*/ +to_string_mm_dd_yyyy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { + assert(len(buf) >= 10) + y, _m, d := date(t) + m := u8(_m) + + buf[9] = '0' + u8(y % 10); y /= 10 + buf[8] = '0' + u8(y % 10); y /= 10 + buf[7] = '0' + u8(y % 10); y /= 10 + buf[6] = '0' + u8(y) + buf[5] = '-' + buf[4] = '0' + u8(d % 10); d /= 10 + buf[3] = '0' + u8(d % 10) + buf[2] = '-' + buf[1] = '0' + u8(m % 10); m /= 10 + buf[0] = '0' + u8(m % 10) + + return string(buf[:10]) +} + +/* +Formats a `Time` as a `mm-dd-yy` date string. + +**Inputs**: +- `t`: The `Time` to format. +- `buf`: The backing buffer to use. + +**Returns**: +- The formatted string `res`, backed by `buf`. + +**Example**: + +In order to format the current date, the following code can be used: + +```odin +buf: [8]u8 +now := time.now() +fmt.println(time.to_string_mm_dd_yy(now, buf[:])) +``` +*/ +to_string_mm_dd_yy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { + assert(len(buf) >= 8) + y, _m, d := date(t) + y %= 100; m := u8(_m) + + buf[7] = '0' + u8(y % 10); y /= 10 + buf[6] = '0' + u8(y) + buf[5] = '-' + buf[4] = '0' + u8(d % 10); d /= 10 + buf[3] = '0' + u8(d % 10) + buf[2] = '-' + buf[1] = '0' + u8(m % 10); m /= 10 + buf[0] = '0' + u8(m % 10) + + return string(buf[:8]) +} + /* Read the timestamp counter of the CPU. */ diff --git a/tests/core/time/test_core_time.odin b/tests/core/time/test_core_time.odin index aeae44ca1..c408bc582 100644 --- a/tests/core/time/test_core_time.odin +++ b/tests/core/time/test_core_time.odin @@ -6,6 +6,43 @@ import dt "core:time/datetime" is_leap_year :: time.is_leap_year +@test +test_time_and_date_formatting :: proc(t: ^testing.T) { + buf: [64]u8 + { + now := time.Time{_nsec=min(i64)} // 1677-09-21 00:12:44.145224192 +0000 UTC + d := time.Duration(now._nsec) + + testing.expect_value(t, time.to_string_hms (now, buf[:]), "00:12:44") + testing.expect_value(t, time.to_string_hms_12 (now, buf[:]), "00:12:44 am") + testing.expect_value(t, time.to_string_hms_12 (now, buf[:], {"㏂", "㏘"}), "00:12:44㏂") + testing.expect_value(t, time.to_string_hms (d, buf[:]), "00:12:44") + + testing.expect_value(t, time.to_string_yyyy_mm_dd(now, buf[:]), "1677-09-21") + testing.expect_value(t, time.to_string_yy_mm_dd (now, buf[:]), "77-09-21") + testing.expect_value(t, time.to_string_dd_mm_yyyy(now, buf[:]), "21-09-1677") + testing.expect_value(t, time.to_string_dd_mm_yy (now, buf[:]), "21-09-77") + testing.expect_value(t, time.to_string_mm_dd_yyyy(now, buf[:]), "09-21-1677") + testing.expect_value(t, time.to_string_mm_dd_yy (now, buf[:]), "09-21-77") + } + { + now := time.Time{_nsec=max(i64)} // 2262-04-11 23:47:16.854775807 +0000 UTC + d := time.Duration(now._nsec) + + testing.expect_value(t, time.to_string_hms (now, buf[:]), "23:47:16") + testing.expect_value(t, time.to_string_hms_12 (now, buf[:]), "11:47:16 pm") + testing.expect_value(t, time.to_string_hms_12 (now, buf[:], {"㏂", "㏘"}), "11:47:16㏘") + testing.expect_value(t, time.to_string_hms (d, buf[:]), "23:47:16") + + testing.expect_value(t, time.to_string_yyyy_mm_dd(now, buf[:]), "2262-04-11") + testing.expect_value(t, time.to_string_yy_mm_dd (now, buf[:]), "62-04-11") + testing.expect_value(t, time.to_string_dd_mm_yyyy(now, buf[:]), "11-04-2262") + testing.expect_value(t, time.to_string_dd_mm_yy (now, buf[:]), "11-04-62") + testing.expect_value(t, time.to_string_mm_dd_yyyy(now, buf[:]), "04-11-2262") + testing.expect_value(t, time.to_string_mm_dd_yy (now, buf[:]), "04-11-62") + } +} + @test test_ordinal_date_roundtrip :: proc(t: ^testing.T) { testing.expect(t, dt.unsafe_ordinal_to_date(dt.unsafe_date_to_ordinal(dt.MIN_DATE)) == dt.MIN_DATE, "Roundtripping MIN_DATE failed.") From ca7d86084ed5014e25185b53983e1381fe902e14 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 25 Jul 2024 20:58:47 +0200 Subject: [PATCH 023/122] Improve docs. --- core/time/time.odin | 321 +++++++++++++++++++------------------------- 1 file changed, 137 insertions(+), 184 deletions(-) diff --git a/core/time/time.odin b/core/time/time.odin index 131629dcb..922a7c307 100644 --- a/core/time/time.odin +++ b/core/time/time.odin @@ -232,27 +232,21 @@ duration_hours :: proc "contextless" (d: Duration) -> f64 { } /* -Round a duration to a specific unit. +Round a duration to a specific unit -This procedure rounds the duration to a specific unit. - -**Inputs**: -- `d`: The duration to round. -- `m`: The unit to round to. - -**Returns**: -- The duration `d`, rounded to the unit specified by `m`. - -**Example**: - -In order to obtain the rough amount of seconds in a duration, the following call -can be used: - -``` -time.duration_round(my_duration, time.Second) -``` +This procedure rounds the duration to a specific unit **Note**: Any duration can be supplied as a unit. + +Inputs: +- d: The duration to round +- m: The unit to round to + +Returns: +- The duration `d`, rounded to the unit specified by `m` + +Example: + time.duration_round(my_duration, time.Second) */ duration_round :: proc "contextless" (d, m: Duration) -> Duration { _less_than_half :: #force_inline proc "contextless" (x, y: Duration) -> bool { @@ -288,23 +282,17 @@ Truncate the duration to the specified unit. This procedure truncates the duration `d` to the unit specified by `m`. -**Inputs**: -- `d`: The duration to truncate. -- `m`: The unit to truncate to. +**Note**: Any duration can be supplied as a unit. -**Returns**: +Inputs: +- d: The duration to truncate. +- m: The unit to truncate to. + +Returns: - The duration `d`, truncated to the unit specified by `m`. -**Example**: - -In order to obtain the amount of whole seconds in a duration, the following call -can be used: - -``` -time.duration_round(my_duration, time.Second) -``` - -**Note**: Any duration can be supplied as a unit. +Example: + time.duration_round(my_duration, time.Second) */ duration_truncate :: proc "contextless" (d, m: Duration) -> Duration { return d if m <= 0 else d - d%m @@ -389,28 +377,30 @@ clock_from_seconds :: proc "contextless" (nsec: u64) -> (hour, min, sec: int) { return } +MIN_HMS_LEN :: 8 +MIN_HMS_12_LEN :: 11 +MIN_YYYY_DATE_LEN :: 10 +MIN_YY_DATE_LEN :: 8 + /* -Formats a `Time` as a 24-hour `HH:MM:SS` string. +Formats a `Time` as a 24-hour `hh:mm:ss` string. -**Inputs**: -- `t`: The `Time` to format. -- `buf`: The backing buffer to use. +**Does not allocate** -**Returns**: -- The formatted string `res`, backed by `buf`. +Inputs: +- t: The Time to format. +- buf: The backing buffer to use. -**Example**: +Returns: +- res: The formatted string, backed by buf -In order to format the current time, the following code can be used: - -```odin -buf: [8]u8 -now := time.now() -fmt.println(time.to_string_hms(now, buf[:])) -``` +Example: + buf: [MIN_HMS_LEN]u8 + now := time.now() + fmt.println(time.to_string_hms(now, buf[:])) */ time_to_string_hms :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { - assert(len(buf) >= 8) + assert(len(buf) >= MIN_HMS_LEN) h, m, s := clock(t) buf[7] = '0' + u8(s % 10); s /= 10 @@ -422,28 +412,25 @@ time_to_string_hms :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check buf[1] = '0' + u8(h % 10); h /= 10 buf[0] = '0' + u8(h) - return string(buf[:8]) + return string(buf[:MIN_HMS_LEN]) } /* -Formats a `Duration` as a 24-hour `HH:MM:SS` string. +Formats a `Duration` as a 24-hour `hh:mm:ss` string. -**Inputs**: -- `d`: The `Duration` to format. -- `buf`: The backing buffer to use. +**Does not allocate** -**Returns**: -- The formatted string `res`, backed by `buf`. +Inputs: +- d: The Duration to format. +- buf: The backing buffer to use. -**Example**: +Returns: +- res: The formatted string, backed by buf -In order to format a duration, the following code can be used: - -```odin -buf: [8]u8 -d := time.since(earlier) -fmt.println(time.to_string_hms(d, buf[:])) -``` +Example: + buf: [MIN_HMS_LEN]u8 + d := time.since(earlier) + fmt.println(time.to_string_hms(now, buf[:])) */ duration_to_string_hms :: proc(d: Duration, buf: []u8) -> (res: string) #no_bounds_check { return time_to_string_hms(Time{_nsec=i64(d)}, buf) @@ -451,31 +438,27 @@ duration_to_string_hms :: proc(d: Duration, buf: []u8) -> (res: string) #no_boun to_string_hms :: proc{time_to_string_hms, duration_to_string_hms} - /* -Formats a `Time` as a 12-hour `HH:MM:SS pm` string. +Formats a `Time` as a 12-hour `hh:mm:ss pm` string -**Inputs**: -- `t`: The `Time` to format. -- `buf`: The backing buffer to use. -- `ampm`: An optional pair of AM/PM strings to use in place of the default. +**Does not allocate** -**Returns**: -- The formatted string `res`, backed by `buf`. +Inputs: +- t: The Time to format +- buf: The backing buffer to use +- ampm: An optional pair of am/pm strings to use in place of the default -**Example**: +Returns: +- res: The formatted string, backed by buf -In order to format the current time, the following code can be used: - -```odin -buf: [64]u8 -now := time.now() -fmt.println(time.to_string_hms_12(now, buf[:])) -fmt.println(time.to_string_hms_12(now, buf[:], {"㏂", "㏘"})) -``` +Example: + buf: [64]u8 + now := time.now() + fmt.println(time.to_string_hms_12(now, buf[:])) + fmt.println(time.to_string_hms_12(now, buf[:], {"㏂", "㏘"})) */ to_string_hms_12 :: proc(t: Time, buf: []u8, ampm: [2]string = {" am", " pm"}) -> (res: string) #no_bounds_check { - assert(len(buf) >= 8 + max(len(ampm[0]), len(ampm[1]))) + assert(len(buf) >= MIN_HMS_LEN + max(len(ampm[0]), len(ampm[1]))) h, m, s := clock(t) _h := h % 12 @@ -490,35 +473,30 @@ to_string_hms_12 :: proc(t: Time, buf: []u8, ampm: [2]string = {" am", " pm"}) - if h < 13 { copy(buf[8:], ampm[0]) - return string(buf[:8+len(ampm[0])]) + return string(buf[:MIN_HMS_LEN+len(ampm[0])]) } else { copy(buf[8:], ampm[1]) - return string(buf[:8+len(ampm[1])]) + return string(buf[:MIN_HMS_LEN+len(ampm[1])]) } } /* -Formats a `Time` as a `yyyy-mm-dd` date string. +Formats a Time as a yyyy-mm-dd date string. -**Inputs**: -- `t`: The `Time` to format. -- `buf`: The backing buffer to use. +Inputs: +- t: The Time to format. +- buf: The backing buffer to use. -**Returns**: -- The formatted string `res`, backed by `buf`. +Returns: +- res: The formatted string, backed by `buf`. -**Example**: - -In order to format the current date, the following code can be used: - -```odin -buf: [10]u8 -now := time.now() -fmt.println(time.to_string_yyyy_mm_dd(now, buf[:])) -``` +Example: + buf: [MIN_YYYY_DATE_LEN]u8 + now := time.now() + fmt.println(time.to_string_yyyy_mm_dd(now, buf[:])) */ to_string_yyyy_mm_dd :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { - assert(len(buf) >= 10) + assert(len(buf) >= MIN_YYYY_DATE_LEN) y, _m, d := date(t) m := u8(_m) @@ -533,31 +511,26 @@ to_string_yyyy_mm_dd :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_che buf[1] = '0' + u8(y % 10); y /= 10 buf[0] = '0' + u8(y) - return string(buf[:10]) + return string(buf[:MIN_YYYY_DATE_LEN]) } /* -Formats a `Time` as a `yy-mm-dd` date string. +Formats a Time as a yy-mm-dd date string. -**Inputs**: -- `t`: The `Time` to format. -- `buf`: The backing buffer to use. +Inputs: +- t: The Time to format. +- buf: The backing buffer to use. -**Returns**: -- The formatted string `res`, backed by `buf`. +Returns: +- res: The formatted string, backed by `buf`. -**Example**: - -In order to format the current date, the following code can be used: - -```odin -buf: [8]u8 -now := time.now() -fmt.println(time.to_string_yy_mm_dd(now, buf[:])) -``` +Example: + buf: [8]u8 + now := time.now() + fmt.println(time.to_string_yy_mm_dd(now, buf[:])) */ to_string_yy_mm_dd :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { - assert(len(buf) >= 8) + assert(len(buf) >= MIN_YY_DATE_LEN) y, _m, d := date(t) y %= 100; m := u8(_m) @@ -570,31 +543,26 @@ to_string_yy_mm_dd :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check buf[1] = '0' + u8(y % 10); y /= 10 buf[0] = '0' + u8(y) - return string(buf[:8]) + return string(buf[:MIN_YY_DATE_LEN]) } /* -Formats a `Time` as a `dd-mm-yyyy` date string. +Formats a Time as a dd-mm-yyyy date string. -**Inputs**: -- `t`: The `Time` to format. -- `buf`: The backing buffer to use. +Inputs: +- t: The Time to format. +- buf: The backing buffer to use. -**Returns**: -- The formatted string `res`, backed by `buf`. +Returns: +- res: The formatted string, backed by `buf`. -**Example**: - -In order to format the current date, the following code can be used: - -```odin -buf: [10]u8 -now := time.now() -fmt.println(time.to_string_dd_mm_yyyy(now, buf[:])) -``` +Example: + buf: [10]u8 + now := time.now() + fmt.println(time.to_string_dd_mm_yyyy(now, buf[:])) */ to_string_dd_mm_yyyy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { - assert(len(buf) >= 10) + assert(len(buf) >= MIN_YYYY_DATE_LEN) y, _m, d := date(t) m := u8(_m) @@ -609,31 +577,26 @@ to_string_dd_mm_yyyy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_che buf[1] = '0' + u8(d % 10); d /= 10 buf[0] = '0' + u8(d % 10) - return string(buf[:10]) + return string(buf[:MIN_YYYY_DATE_LEN]) } /* -Formats a `Time` as a `dd-mm-yy` date string. +Formats a Time as a dd-mm-yy date string. -**Inputs**: -- `t`: The `Time` to format. -- `buf`: The backing buffer to use. +Inputs: +- t: The Time to format. +- buf: The backing buffer to use. -**Returns**: -- The formatted string `res`, backed by `buf`. +Returns: +- res: The formatted string, backed by `buf`. -**Example**: - -In order to format the current date, the following code can be used: - -```odin -buf: [8]u8 -now := time.now() -fmt.println(time.to_string_dd_mm_yy(now, buf[:])) -``` +Example: + buf: [8]u8 + now := time.now() + fmt.println(time.to_string_dd_mm_yy(now, buf[:])) */ to_string_dd_mm_yy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { - assert(len(buf) >= 8) + assert(len(buf) >= MIN_YY_DATE_LEN) y, _m, d := date(t) y %= 100; m := u8(_m) @@ -646,31 +609,26 @@ to_string_dd_mm_yy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check buf[1] = '0' + u8(d % 10); d /= 10 buf[0] = '0' + u8(d % 10) - return string(buf[:8]) + return string(buf[:MIN_YY_DATE_LEN]) } /* -Formats a `Time` as a `mm-dd-yyyy` date string. +Formats a Time as a mm-dd-yyyy date string. -**Inputs**: -- `t`: The `Time` to format. -- `buf`: The backing buffer to use. +Inputs: +- t: The Time to format. +- buf: The backing buffer to use. -**Returns**: -- The formatted string `res`, backed by `buf`. +Returns: +- res: The formatted string, backed by `buf`. -**Example**: - -In order to format the current date, the following code can be used: - -```odin -buf: [10]u8 -now := time.now() -fmt.println(time.to_string_mm_dd_yyyy(now, buf[:])) -``` +Example: + buf: [10]u8 + now := time.now() + fmt.println(time.to_string_mm_dd_yyyy(now, buf[:])) */ to_string_mm_dd_yyyy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { - assert(len(buf) >= 10) + assert(len(buf) >= MIN_YYYY_DATE_LEN) y, _m, d := date(t) m := u8(_m) @@ -685,31 +643,26 @@ to_string_mm_dd_yyyy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_che buf[1] = '0' + u8(m % 10); m /= 10 buf[0] = '0' + u8(m % 10) - return string(buf[:10]) + return string(buf[:MIN_YYYY_DATE_LEN]) } /* -Formats a `Time` as a `mm-dd-yy` date string. +Formats a Time as a mm-dd-yy date string. -**Inputs**: -- `t`: The `Time` to format. -- `buf`: The backing buffer to use. +Inputs: +- t: The Time to format. +- buf: The backing buffer to use. -**Returns**: -- The formatted string `res`, backed by `buf`. +Returns: +- res: The formatted string, backed by `buf`. -**Example**: - -In order to format the current date, the following code can be used: - -```odin -buf: [8]u8 -now := time.now() -fmt.println(time.to_string_mm_dd_yy(now, buf[:])) -``` +Example: + buf: [8]u8 + now := time.now() + fmt.println(time.to_string_mm_dd_yy(now, buf[:])) */ to_string_mm_dd_yy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check { - assert(len(buf) >= 8) + assert(len(buf) >= MIN_YY_DATE_LEN) y, _m, d := date(t) y %= 100; m := u8(_m) @@ -722,7 +675,7 @@ to_string_mm_dd_yy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check buf[1] = '0' + u8(m % 10); m /= 10 buf[0] = '0' + u8(m % 10) - return string(buf[:8]) + return string(buf[:MIN_YY_DATE_LEN]) } /* From 00c6b83537aba54f63b92a009dde6fbd0343a8e0 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 25 Jul 2024 21:02:38 +0200 Subject: [PATCH 024/122] Use constants in example. --- core/time/time.odin | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/time/time.odin b/core/time/time.odin index 922a7c307..e4ec67be3 100644 --- a/core/time/time.odin +++ b/core/time/time.odin @@ -525,7 +525,7 @@ Returns: - res: The formatted string, backed by `buf`. Example: - buf: [8]u8 + buf: [MIN_YY_DATE_LEN]u8 now := time.now() fmt.println(time.to_string_yy_mm_dd(now, buf[:])) */ @@ -557,7 +557,7 @@ Returns: - res: The formatted string, backed by `buf`. Example: - buf: [10]u8 + buf: [MIN_YYYY_DATE_LEN]u8 now := time.now() fmt.println(time.to_string_dd_mm_yyyy(now, buf[:])) */ @@ -591,7 +591,7 @@ Returns: - res: The formatted string, backed by `buf`. Example: - buf: [8]u8 + buf: [MIN_YY_DATE_LEN]u8 now := time.now() fmt.println(time.to_string_dd_mm_yy(now, buf[:])) */ @@ -623,7 +623,7 @@ Returns: - res: The formatted string, backed by `buf`. Example: - buf: [10]u8 + buf: [MIN_YYYY_DATE_LEN]u8 now := time.now() fmt.println(time.to_string_mm_dd_yyyy(now, buf[:])) */ @@ -657,7 +657,7 @@ Returns: - res: The formatted string, backed by `buf`. Example: - buf: [8]u8 + buf: [MIN_YY_DATE_LEN]u8 now := time.now() fmt.println(time.to_string_mm_dd_yy(now, buf[:])) */ From 58ab6e5f94f8aa6f0b8186e4b15b0e711921c1d8 Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Fri, 26 Jul 2024 10:07:20 +0200 Subject: [PATCH 025/122] missign cursorinfo --- core/sys/windows/user32.odin | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 656da86ed..02cf0a54d 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -287,6 +287,8 @@ foreign user32 { CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN --- GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int --- + GetCursorInfo :: proc(pci: PCURSORINFO) -> BOOL --- + GetSystemMenu :: proc(hWnd: HWND, bRevert: BOOL) -> HMENU --- EnableMenuItem :: proc(hMenu: HMENU, uIDEnableItem: UINT, uEnable: UINT) -> BOOL --- MenuItemFromPoint :: proc(hWnd: HWND, hMenu: HMENU, ptScreen: POINT) -> INT --- @@ -371,6 +373,10 @@ GET_XBUTTON_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> WORD return HIWORD(cast(DWORD)wParam) } +GET_RAWINPUT_CODE_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> BYTE { + return BYTE(wParam) & 0xFF +} + MAKEINTRESOURCEW :: #force_inline proc "contextless" (#any_int i: int) -> LPWSTR { return cast(LPWSTR)uintptr(WORD(i)) } @@ -569,6 +575,15 @@ WINDOWINFO :: struct { } PWINDOWINFO :: ^WINDOWINFO +CURSORINFO :: struct { + cbSize: DWORD, + flags: DWORD, + hCursor: HCURSOR, + ptScreenPos: POINT, +} +PCURSORINFO :: ^CURSORINFO + + DRAWTEXTPARAMS :: struct { cbSize: UINT, iTabLength: INT, From 6e6f2a1f6b3e1e24d3ecc471e86bde798878fad4 Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Fri, 26 Jul 2024 10:14:13 +0200 Subject: [PATCH 026/122] removed obsolete fiels on WIN32_FIND_DATAW to match the size from the winsdk headers --- core/sys/windows/types.odin | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 591041aed..e10e53cf9 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -1141,9 +1141,6 @@ WIN32_FIND_DATAW :: struct { dwReserved1: DWORD, cFileName: [MAX_PATH]WCHAR, cAlternateFileName: [14]WCHAR, - _OBSOLETE_dwFileType: DWORD, // Obsolete. Do not use. - _OBSOLETE_dwCreatorType: DWORD, // Obsolete. Do not use - _OBSOLETE_wFinderFlags: WORD, // Obsolete. Do not use } FILE_ID_128 :: struct { From 03f3ea5a9e40b4636238ee840845b66a585ad5e4 Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Fri, 26 Jul 2024 10:43:26 +0200 Subject: [PATCH 027/122] removed old test stuff --- tests/core/sys/windows/test_windows.odin | 68 +----------------------- 1 file changed, 1 insertion(+), 67 deletions(-) diff --git a/tests/core/sys/windows/test_windows.odin b/tests/core/sys/windows/test_windows.odin index 168618144..724b1b7af 100644 --- a/tests/core/sys/windows/test_windows.odin +++ b/tests/core/sys/windows/test_windows.odin @@ -1,48 +1,13 @@ //+build windows package test_core_sys_windows -import "core:fmt" import "base:intrinsics" -import "core:os" import "base:runtime" import win32 "core:sys/windows" import "core:testing" L :: intrinsics.constant_utf16_cstring - -TEST_count := 0 -TEST_fail := 0 - -t := &testing.T{} - -when ODIN_TEST { - expect :: testing.expect - expectf :: testing.expectf - log :: testing.log - fmt :: fmt -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - expectf :: proc( - t: ^testing.T, condition: bool, format: string, args: ..any, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf(format, ..args) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} +expectf :: testing.expectf @(private) expect_size :: proc(t: ^testing.T, $act: typeid, exp: int, loc := #caller_location) { @@ -79,34 +44,3 @@ expect_value_str :: proc(t: ^testing.T, wact, wexp: win32.wstring, loc := #calle expectf(t, err == .None, "0x%8X (should be: 0x%8X)", err, 0, loc = loc) expectf(t, act == exp, "0x%8X (should be: 0x%8X)", act, exp, loc = loc) } - -main :: proc() { - verify_win32_type_sizes(t) - verify_macros(t) - verify_winnt(t) - verify_winuser(t) - verify_gdi32(t) - verify_winmm(t) - verify_advapi32(t) - verify_winnls(t) - verify_winreg(t) - verify_verrsrc(t) - verify_error_codes(t) - verify_error_helpers(t) - - lcid_to_local(t) - - string_from_clsid(t) - clsid_from_string(t) - string_from_iid(t) - iid_from_string(t) - verify_coinit(t) - - make_hresult(t) - decode_hresult(t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} From fe587ee79a891bb2ae9a0ae43aef4351a1f1aafa Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Fri, 26 Jul 2024 11:04:13 +0200 Subject: [PATCH 028/122] try to add sys/windows to the normal core tests --- tests/core/normal.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/core/normal.odin b/tests/core/normal.odin index 065090be3..7d5795273 100644 --- a/tests/core/normal.odin +++ b/tests/core/normal.odin @@ -36,6 +36,7 @@ download_assets :: proc() { @(require) import "slice" @(require) import "strconv" @(require) import "strings" +@(require) import "sys/windows" @(require) import "text/i18n" @(require) import "text/match" @(require) import "thread" From 271ec643ed986f1d3e5c7c6915b90488c6912d20 Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Fri, 26 Jul 2024 11:30:48 +0200 Subject: [PATCH 029/122] removed some comments --- tests/core/sys/windows/test_ole32.odin | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/core/sys/windows/test_ole32.odin b/tests/core/sys/windows/test_ole32.odin index eb01c4489..30bf5bc80 100644 --- a/tests/core/sys/windows/test_ole32.odin +++ b/tests/core/sys/windows/test_ole32.odin @@ -60,8 +60,3 @@ verify_coinit :: proc(t: ^testing.T) { expect_value(t, win32.COINIT.DISABLE_OLE1DDE, 0x00000004) expect_value(t, win32.COINIT.SPEED_OVER_MEMORY, 0x00000008) } - -// hr := CoInitializeEx(nil, .MULTITHREADED); -// testing.expectf(t, hr == 0, "%x (should be: %v)", u32(hr), 0) -// assert(SUCCEEDED(hr)) -// defer CoUninitialize() From 1d598f82873ca0519b79e8e36f79d7ef86bf85ab Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 28 Jul 2024 01:23:47 -0700 Subject: [PATCH 030/122] tweak doc a little to reduce onboarding friction for thread-users --- core/prof/spall/doc.odin | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/prof/spall/doc.odin b/core/prof/spall/doc.odin index c34ba0d5b..479ee7e46 100644 --- a/core/prof/spall/doc.odin +++ b/core/prof/spall/doc.odin @@ -1,8 +1,9 @@ /* import "core:prof/spall" + import "core:sync" spall_ctx: spall.Context - spall_buffer: spall.Buffer + @(thread_local) spall_buffer: spall.Buffer foo :: proc() { spall.SCOPED_EVENT(&spall_ctx, &spall_buffer, #procedure) @@ -13,7 +14,7 @@ defer spall.context_destroy(&spall_ctx) buffer_backing := make([]u8, spall.BUFFER_DEFAULT_SIZE) - spall_buffer = spall.buffer_create(buffer_backing) + spall_buffer = spall.buffer_create(buffer_backing, sync.current_thread_id) defer spall.buffer_destroy(&spall_ctx, &spall_buffer) spall.SCOPED_EVENT(&spall_ctx, &spall_buffer, #procedure) From 27f75c40abdb6172e1b498b432555c2d5d3ba415 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 28 Jul 2024 01:29:33 -0700 Subject: [PATCH 031/122] make example compile --- core/prof/spall/doc.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/prof/spall/doc.odin b/core/prof/spall/doc.odin index 479ee7e46..d9259465b 100644 --- a/core/prof/spall/doc.odin +++ b/core/prof/spall/doc.odin @@ -1,4 +1,5 @@ /* + import "base:runtime" import "core:prof/spall" import "core:sync" @@ -14,7 +15,7 @@ defer spall.context_destroy(&spall_ctx) buffer_backing := make([]u8, spall.BUFFER_DEFAULT_SIZE) - spall_buffer = spall.buffer_create(buffer_backing, sync.current_thread_id) + spall_buffer = spall.buffer_create(buffer_backing, u32(sync.current_thread_id())) defer spall.buffer_destroy(&spall_ctx, &spall_buffer) spall.SCOPED_EVENT(&spall_ctx, &spall_buffer, #procedure) From 24e6f16f4aa574b182e4ec2361b22b4c3d71e34c Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 28 Jul 2024 15:00:29 +0200 Subject: [PATCH 032/122] Clamp dot in `angle_between` to avoid precision errors. Fixes #3978 --- core/math/linalg/general.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index 90fe7332c..7587ad63f 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -275,7 +275,8 @@ to_ptr :: proc{vector_to_ptr, matrix_to_ptr} vector_angle_between :: proc "contextless" (a, b: $V/[$N]$E) -> E { a0 := normalize0(a) b0 := normalize0(b) - return math.acos(dot(a0, b0)) + d := clamp(dot(a0, b0), -1, +1) + return math.acos(d) } quaternion64_angle_between :: proc "contextless" (a, b: $Q/quaternion64) -> f16 { c := normalize0(conj(a) * b) From 4d1d754caeb421da9a289fee613aea16867f14ce Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Mon, 29 Jul 2024 02:21:26 +0200 Subject: [PATCH 033/122] fix `specific_union_variant in map_keyed_by_union` not converting to union type --- src/llvm_backend.cpp | 10 ++++++---- tests/internal/test_map.odin | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 9fa570eaf..72ba12516 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -976,14 +976,16 @@ gb_internal lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) { gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue const &map_ptr, lbValue key, lbValue *key_ptr_) { TEMPORARY_ALLOCATOR_GUARD(); - lbValue key_ptr = lb_address_from_load_or_generate_local(p, key); + Type* key_type = base_type(type_deref(map_ptr.type))->Map.key; + + lbValue real_key = lb_emit_conv(p, key, key_type); + + lbValue key_ptr = lb_address_from_load_or_generate_local(p, real_key); key_ptr = lb_emit_conv(p, key_ptr, t_rawptr); if (key_ptr_) *key_ptr_ = key_ptr; - Type* key_type = base_type(type_deref(map_ptr.type))->Map.key; - - lbValue hashed_key = lb_const_hash(p->module, key, key_type); + lbValue hashed_key = lb_const_hash(p->module, real_key, key_type); if (hashed_key.value == nullptr) { lbValue hasher = lb_hasher_proc_for_type(p->module, key_type); diff --git a/tests/internal/test_map.odin b/tests/internal/test_map.odin index 9bd5d34ea..4d305024e 100644 --- a/tests/internal/test_map.odin +++ b/tests/internal/test_map.odin @@ -317,3 +317,23 @@ set_delete_random_key_value :: proc(t: ^testing.T) { seed_incr += 1 } } + +@test +test_union_key_should_not_be_hashing_specifc_variant :: proc(t: ^testing.T) { + Vec2 :: [2]f32 + BoneId :: distinct int + VertexId :: distinct int + Id :: union { + BoneId, + VertexId, + } + + m: map[Id]Vec2 + defer delete(m) + + bone_1: BoneId = 69 + m[bone_1] = {4, 20} + + testing.expect_value(t, bone_1 in m, true) + testing.expect_value(t, Id(bone_1) in m, true) +} From 478b2d7444429165952f3dbca8737b0e464db0e7 Mon Sep 17 00:00:00 2001 From: Damian Tarnawski Date: Mon, 29 Jul 2024 22:14:42 +0200 Subject: [PATCH 034/122] Correct the Array_Type.len comment and assign tok when making Ellipsis node --- core/odin/ast/ast.odin | 2 +- core/odin/parser/parser.odin | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 0ae822e21..31e8fdd53 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -757,7 +757,7 @@ Array_Type :: struct { using node: Expr, open: tokenizer.Pos, tag: ^Expr, - len: ^Expr, // Ellipsis node for [?]T array types, nil for slice types + len: ^Expr, // Unary_Expr node for [?]T array types, nil for slice types close: tokenizer.Pos, elem: ^Expr, } diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 4d045f785..24c85a19e 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1778,6 +1778,7 @@ parse_var_type :: proc(p: ^Parser, flags: ast.Field_Flags) -> ^ast.Expr { type = ast.new(ast.Bad_Expr, tok.pos, end_pos(tok)) } e := ast.new(ast.Ellipsis, type.pos, type) + e.tok = tok.kind e.expr = type return e } From 3aac4b1a3e7c7afe7ee94ec0c2aead0895920331 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sat, 27 Jul 2024 22:15:27 +1100 Subject: [PATCH 035/122] [sync]: Document all procedures --- core/sync/atomic.odin | 472 +++++++++++++++++++++++++++++++++++--- core/sync/doc.odin | 21 ++ core/sync/extended.odin | 469 ++++++++++++++++++++++++++++++------- core/sync/primitives.odin | 470 ++++++++++++++++++++++++++++++++----- 4 files changed, 1262 insertions(+), 170 deletions(-) create mode 100644 core/sync/doc.odin diff --git a/core/sync/atomic.odin b/core/sync/atomic.odin index 65d063f15..7e514a6b4 100644 --- a/core/sync/atomic.odin +++ b/core/sync/atomic.odin @@ -2,44 +2,452 @@ package sync import "base:intrinsics" +/* +This procedure may lower CPU consumption or yield to a hyperthreaded twin +processor. It's exact function is architecture specific, but the intent is to +say that you're not doing much on a CPU. +*/ cpu_relax :: intrinsics.cpu_relax /* -Atomic_Memory_Order :: enum { - Relaxed = 0, // Unordered - Consume = 1, // Monotonic - Acquire = 2, - Release = 3, - Acq_Rel = 4, - Seq_Cst = 5, -} +Describes memory ordering for an atomic operation. + +Modern CPU's contain multiple cores and caches specific to those cores. When a +core performs a write to memory, the value is written to cache first. The issue +is that a core doesn't typically see what's inside the caches of other cores. +In order to make operations consistent CPU's implement mechanisms that +synchronize memory operations across cores by asking other cores or by +pushing data about writes to other cores. + +Due to how these algorithms are implemented, the stores and loads performed by +one core may seem to happen in a different order to another core. It also may +happen that a core reorders stores and loads (independent of how compiler put +them into the machine code). This can cause issues when trying to synchronize +multiple memory locations between two cores. Which is why CPU's allow for +stronger memory ordering guarantees if certain instructions or instruction +variants are used. + +In Odin there are 5 different memory ordering guaranties that can be provided +to an atomic operation: + +- `Relaxed`: The memory access (load or store) is unordered with respect to + other memory accesses. This can be used to implement an atomic counter. + Multiple threads access a single variable, but it doesn't matter when + exactly it gets incremented, because it will become eventually consistent. +- `Consume`: No loads or stores dependent on a memory location can be + reordered before a load with consume memory order. If other threads released + the same memory, it becomes visible. +- `Acquire`: No loads or stores on a memory location can be reordered before a + load of that memory location with acquire memory ordering. If other threads + release the same memory, it becomes visible. +- `Release`: No loads or stores on a memory location can be reordered after a + store of that memory location with release memory ordering. All threads that + acquire the same memory location will see all writes done by the current + thread. +- `Acq_Rel`: Acquire-release memory ordering: combines acquire and release + memory orderings in the same operation. +- `Seq_Cst`: Sequential consistency. The strongest memory ordering. A load will + always be an acquire operation, a store will always be a release operation, + and in addition to that all threads observe the same order of writes. + +Non-explicit atomics will always be sequentially consistent. + + Atomic_Memory_Order :: enum { + Relaxed = 0, // Unordered + Consume = 1, // Monotonic + Acquire = 2, + Release = 3, + Acq_Rel = 4, + Seq_Cst = 5, + } + +**Note(i386, x64)**: x86 has a very strong memory model by default. It +guarantees that all writes are ordered, stores and loads aren't reordered. In +a sense, all operations are at least acquire and release operations. If `lock` +prefix is used, all operations are sequentially consistent. If you use explicit +atomics, make sure you have the correct atomic memory order, because bugs likely +will not show up in x86, but may show up on e.g. arm. More on x86 memory +ordering can be found +[[here; https://www.cs.cmu.edu/~410-f10/doc/Intel_Reordering_318147.pdf]] */ Atomic_Memory_Order :: intrinsics.Atomic_Memory_Order +/* +Establish memory ordering. -atomic_thread_fence :: intrinsics.atomic_thread_fence -atomic_signal_fence :: intrinsics.atomic_signal_fence -atomic_store :: intrinsics.atomic_store -atomic_store_explicit :: intrinsics.atomic_store_explicit -atomic_load :: intrinsics.atomic_load -atomic_load_explicit :: intrinsics.atomic_load_explicit -atomic_add :: intrinsics.atomic_add -atomic_add_explicit :: intrinsics.atomic_add_explicit -atomic_sub :: intrinsics.atomic_sub -atomic_sub_explicit :: intrinsics.atomic_sub_explicit -atomic_and :: intrinsics.atomic_and -atomic_and_explicit :: intrinsics.atomic_and_explicit -atomic_nand :: intrinsics.atomic_nand -atomic_nand_explicit :: intrinsics.atomic_nand_explicit -atomic_or :: intrinsics.atomic_or -atomic_or_explicit :: intrinsics.atomic_or_explicit -atomic_xor :: intrinsics.atomic_xor -atomic_xor_explicit :: intrinsics.atomic_xor_explicit -atomic_exchange :: intrinsics.atomic_exchange -atomic_exchange_explicit :: intrinsics.atomic_exchange_explicit +This procedure establishes memory ordering, without an associated atomic +operation. +*/ +atomic_thread_fence :: intrinsics.atomic_thread_fence -// Returns value and optional ok boolean -atomic_compare_exchange_strong :: intrinsics.atomic_compare_exchange_strong +/* +Establish memory ordering between a current thread and a signal handler. + +This procedure establishes memory ordering between a thread and a signal +handler, that run on the same thread, without an associated atomic operation. +This procedure is equivalent to `atomic_thread_fence`, except it doesn't +issue any CPU instructions for memory ordering. +*/ +atomic_signal_fence :: intrinsics.atomic_signal_fence + +/* +Atomically store a value into memory. + +This procedure stores a value to a memory location in such a way that no other +thread is able to see partial reads. This operation is sequentially-consistent. +*/ +atomic_store :: intrinsics.atomic_store + +/* +Atomically store a value into memory with explicit memory ordering. + +This procedure stores a value to a memory location in such a way that no other +thread is able to see partial reads. The memory ordering of this operation is +as specified by the `order` parameter. +*/ +atomic_store_explicit :: intrinsics.atomic_store_explicit + +/* +Atomically load a value from memory. + +This procedure loads a value from a memory location in such a way that the +received value is not a partial read. The memory ordering of this operation is +sequentially-consistent. +*/ +atomic_load :: intrinsics.atomic_load + +/* +Atomically load a value from memory with explicit memory ordering. + +This procedure loads a value from a memory location in such a way that the +received value is not a partial read. The memory ordering of this operation +is as specified by the `order` parameter. +*/ +atomic_load_explicit :: intrinsics.atomic_load_explicit + +/* +Atomically add a value to the value stored in memory. + +This procedure loads a value from memory, adds the specified value to it, and +stores it back as an atomic operation. This operation is an atomic equivalent +of the following: + + dst^ += val + +The memory ordering of this operation is sequentially-consistent. +*/ +atomic_add :: intrinsics.atomic_add + +/* +Atomically add a value to the value stored in memory. + +This procedure loads a value from memory, adds the specified value to it, and +stores it back as an atomic operation. This operation is an atomic equivalent +of the following: + + dst^ += val + +The memory ordering of this operation is as specified by the `order` parameter. +*/ +atomic_add_explicit :: intrinsics.atomic_add_explicit + +/* +Atomically subtract a value from the value stored in memory. + +This procedure loads a value from memory, subtracts the specified value from it, +and stores the result back as an atomic operation. This operation is an atomic +equivalent of the following: + + dst^ -= val + +The memory ordering of this operation is sequentially-consistent. +*/ +atomic_sub :: intrinsics.atomic_sub + +/* +Atomically subtract a value from the value stored in memory. + +This procedure loads a value from memory, subtracts the specified value from it, +and stores the result back as an atomic operation. This operation is an atomic +equivalent of the following: + + dst^ -= val + +The memory ordering of this operation is as specified by the `order` parameter. +*/ +atomic_sub_explicit :: intrinsics.atomic_sub_explicit + +/* +Atomically replace the memory location with the result of AND operation with +the specified value. + +This procedure loads a value from memory, calculates the result of AND operation +between the loaded value and the specified value, and stores it back into the +same memory location as an atomic operation. This operation is an atomic +equivalent of the following: + + dst^ &= val + +The memory ordering of this operation is sequentially-consistent. +*/ +atomic_and :: intrinsics.atomic_and + +/* +Atomically replace the memory location with the result of AND operation with +the specified value. + +This procedure loads a value from memory, calculates the result of AND operation +between the loaded value and the specified value, and stores it back into the +same memory location as an atomic operation. This operation is an atomic +equivalent of the following: + + dst^ &= val + +The memory ordering of this operation is as specified by the `order` parameter. +*/ +atomic_and_explicit :: intrinsics.atomic_and_explicit + +/* +Atomically replace the memory location with the result of NAND operation with +the specified value. + +This procedure loads a value from memory, calculates the result of NAND operation +between the loaded value and the specified value, and stores it back into the +same memory location as an atomic operation. This operation is an atomic +equivalent of the following: + + dst^ = ~(dst^ & val) + +The memory ordering of this operation is sequentially-consistent. +*/ +atomic_nand :: intrinsics.atomic_nand + +/* +Atomically replace the memory location with the result of NAND operation with +the specified value. + +This procedure loads a value from memory, calculates the result of NAND operation +between the loaded value and the specified value, and stores it back into the +same memory location as an atomic operation. This operation is an atomic +equivalent of the following: + + dst^ = ~(dst^ & val) + +The memory ordering of this operation is as specified by the `order` parameter. +*/ +atomic_nand_explicit :: intrinsics.atomic_nand_explicit + +/* +Atomically replace the memory location with the result of OR operation with +the specified value. + +This procedure loads a value from memory, calculates the result of OR operation +between the loaded value and the specified value, and stores it back into the +same memory location as an atomic operation. This operation is an atomic +equivalent of the following: + + dst^ |= val + +The memory ordering of this operation is sequentially-consistent. +*/ +atomic_or :: intrinsics.atomic_or + +/* +Atomically replace the memory location with the result of OR operation with +the specified value. + +This procedure loads a value from memory, calculates the result of OR operation +between the loaded value and the specified value, and stores it back into the +same memory location as an atomic operation. This operation is an atomic +equivalent of the following: + + dst^ |= val + +The memory ordering of this operation is as specified by the `order` parameter. +*/ +atomic_or_explicit :: intrinsics.atomic_or_explicit + +/* +Atomically replace the memory location with the result of XOR operation with +the specified value. + +This procedure loads a value from memory, calculates the result of XOR operation +between the loaded value and the specified value, and stores it back into the +same memory location as an atomic operation. This operation is an atomic +equivalent of the following: + + dst^ ~= val + +The memory ordering of this operation is sequentially-consistent. +*/ +atomic_xor :: intrinsics.atomic_xor + +/* +Atomically replace the memory location with the result of XOR operation with +the specified value. + +This procedure loads a value from memory, calculates the result of XOR operation +between the loaded value and the specified value, and stores it back into the +same memory location as an atomic operation. This operation is an atomic +equivalent of the following: + + dst^ ~= val + +The memory ordering of this operation is as specified by the `order` parameter. +*/ +atomic_xor_explicit :: intrinsics.atomic_xor_explicit + +/* +Atomically exchange the value in a memory location, with the specified value. + +This procedure loads a value from the specified memory location, and stores the +specified value into that memory location. Then the loaded value is returned, +all done in a single atomic operation. This operation is an atomic equivalent +of the following: + + tmp := dst^ + dst^ = val + return tmp + +The memory ordering of this operation is sequentially-consistent. +*/ +atomic_exchange :: intrinsics.atomic_exchange + +/* +Atomically exchange the value in a memory location, with the specified value. + +This procedure loads a value from the specified memory location, and stores the +specified value into that memory location. Then the loaded value is returned, +all done in a single atomic operation. This operation is an atomic equivalent +of the following: + + tmp := dst^ + dst^ = val + return tmp + +The memory ordering of this operation is as specified by the `order` parameter. +*/ +atomic_exchange_explicit :: intrinsics.atomic_exchange_explicit + +/* +Atomically compare and exchange the value with a memory location. + +This procedure checks if the value pointed to by the `dst` parameter is equal +to `old`, and if they are, it stores the value `new` into the memory location, +all done in a single atomic operation. This procedure returns the old value +stored in a memory location and a boolean value signifying whether `old` was +equal to `new`. + +This procedure is an atomic equivalent of the following operation: + + old_dst := dst^ + if old_dst == old { + dst^ = new + return old_dst, true + } else { + return old_dst, false + } + +The strong version of compare exchange always returns true, when the returned +old value stored in location pointed to by `dst` and the `old` parameter are +equal. + +Atomic compare exchange has two memory orderings: One is for the +read-modify-write operation, if the comparison succeeds, and the other is for +the load operation, if the comparison fails. The memory ordering for both of +of these operations is sequentially-consistent. +*/ +atomic_compare_exchange_strong :: intrinsics.atomic_compare_exchange_strong + +/* +Atomically compare and exchange the value with a memory location. + +This procedure checks if the value pointed to by the `dst` parameter is equal +to `old`, and if they are, it stores the value `new` into the memory location, +all done in a single atomic operation. This procedure returns the old value +stored in a memory location and a boolean value signifying whether `old` was +equal to `new`. + +This procedure is an atomic equivalent of the following operation: + + old_dst := dst^ + if old_dst == old { + dst^ = new + return old_dst, true + } else { + return old_dst, false + } + +The strong version of compare exchange always returns true, when the returned +old value stored in location pointed to by `dst` and the `old` parameter are +equal. + +Atomic compare exchange has two memory orderings: One is for the +read-modify-write operation, if the comparison succeeds, and the other is for +the load operation, if the comparison fails. The memory ordering for these +operations is as specified by `success` and `failure` parameters respectively. +*/ atomic_compare_exchange_strong_explicit :: intrinsics.atomic_compare_exchange_strong_explicit -atomic_compare_exchange_weak :: intrinsics.atomic_compare_exchange_weak -atomic_compare_exchange_weak_explicit :: intrinsics.atomic_compare_exchange_weak_explicit \ No newline at end of file + +/* +Atomically compare and exchange the value with a memory location. + +This procedure checks if the value pointed to by the `dst` parameter is equal +to `old`, and if they are, it stores the value `new` into the memory location, +all done in a single atomic operation. This procedure returns the old value +stored in a memory location and a boolean value signifying whether `old` was +equal to `new`. + +This procedure is an atomic equivalent of the following operation: + + old_dst := dst^ + if old_dst == old { + // may return false here + dst^ = new + return old_dst, true + } else { + return old_dst, false + } + +The weak version of compare exchange may return false, even if `dst^ == old`. +On some platforms running weak compare exchange in a loop is faster than a +strong version. + +Atomic compare exchange has two memory orderings: One is for the +read-modify-write operation, if the comparison succeeds, and the other is for +the load operation, if the comparison fails. The memory ordering for both +of these operations is sequentially-consistent. +*/ +atomic_compare_exchange_weak :: intrinsics.atomic_compare_exchange_weak + +/* +Atomically compare and exchange the value with a memory location. + +This procedure checks if the value pointed to by the `dst` parameter is equal +to `old`, and if they are, it stores the value `new` into the memory location, +all done in a single atomic operation. This procedure returns the old value +stored in a memory location and a boolean value signifying whether `old` was +equal to `new`. + +This procedure is an atomic equivalent of the following operation: + + old_dst := dst^ + if old_dst == old { + // may return false here + dst^ = new + return old_dst, true + } else { + return old_dst, false + } + +The weak version of compare exchange may return false, even if `dst^ == old`. +On some platforms running weak compare exchange in a loop is faster than a +strong version. + +Atomic compare exchange has two memory orderings: One is for the +read-modify-write operation, if the comparison succeeds, and the other is for +the load operation, if the comparison fails. The memory ordering for these +operations is as specified by the `success` and `failure` parameters +respectively. +*/ +atomic_compare_exchange_weak_explicit :: intrinsics.atomic_compare_exchange_weak_explicit \ No newline at end of file diff --git a/core/sync/doc.odin b/core/sync/doc.odin new file mode 100644 index 000000000..9876c46fb --- /dev/null +++ b/core/sync/doc.odin @@ -0,0 +1,21 @@ +/* +Synchronization primitives + +This package implements various synchronization primitives that can be used to +synchronize threads' access to shared memory. + +To limit or control the threads' access to shared memory typically the +following approaches are used: + +* Locks +* Lock-free + +When using locks, sections of the code that access shared memory (also known as +**critical sections**) are guarded by locks, allowing limited access to threads +and blocking the execution of any other threads. + +In lock-free programming the data itself is organized in such a way that threads +don't intervene much. It can be done via segmenting the data between threads, +and/or by using atomic operations. +*/ +package sync \ No newline at end of file diff --git a/core/sync/extended.odin b/core/sync/extended.odin index 781ed816e..b446fefa0 100644 --- a/core/sync/extended.odin +++ b/core/sync/extended.odin @@ -4,15 +4,41 @@ import "core:time" import vg "core:sys/valgrind" _ :: vg -// A Wait_Group waits for a collection of threads to finish -// -// A Wait_Group must not be copied after first use +/* +Wait group. + +Wait group is a synchronization primitive used by the waiting thread to wait, +until a all working threads finish work. + +The waiting thread first sets the number of working threads it will expect to +wait for using `wait_group_add` call, and start waiting using `wait_group_wait` +call. When worker threads complete their work, each of them will call +`wait_group_done`, and after all working threads have called this procedure, +the waiting thread will resume execution. + +For the purpose of keeping track whether all working threads have finished their +work, the wait group keeps an internal atomic counter. Initially, the waiting +thread might set it to a certain non-zero amount. When each working thread +completes the work, the internal counter is atomically decremented until it +reaches zero. When it reaches zero, the waiting thread is unblocked. The counter +is not allowed to become negative. + +**Note**: Just like any synchronization primitives, a wait group cannot be +copied after first use. See documentation for `Mutex` or `Cond`. +*/ Wait_Group :: struct #no_copy { counter: int, mutex: Mutex, cond: Cond, } +/* +Increment an internal counter of a wait group. + +This procedure atomicaly increments a number to the specified wait group's +internal counter by a specified amount. This operation can be done on any +thread. +*/ wait_group_add :: proc "contextless" (wg: ^Wait_Group, delta: int) { if delta == 0 { return @@ -32,10 +58,23 @@ wait_group_add :: proc "contextless" (wg: ^Wait_Group, delta: int) { } } +/* +Signal work done by a thread in a wait group. + +This procedure decrements the internal counter of the specified wait group and +wakes up the waiting thread. Once the internal counter reaches zero, the waiting +thread resumes execution. +*/ wait_group_done :: proc "contextless" (wg: ^Wait_Group) { wait_group_add(wg, -1) } +/* +Wait for all worker threads in the wait group. + +This procedure blocks the execution of the current thread, until the specified +wait group's internal counter reaches zero. +*/ wait_group_wait :: proc "contextless" (wg: ^Wait_Group) { guard(&wg.mutex) @@ -47,6 +86,14 @@ wait_group_wait :: proc "contextless" (wg: ^Wait_Group) { } } +/* +Wait for all worker threads in the wait group, or until timeout is reached. + +This procedure blocks the execution of the current thread, until the specified +wait group's internal counter reaches zero, or until the timeout is reached. + +This procedure returns `false`, if the timeout was reached, `true` otherwise. +*/ wait_group_wait_with_timeout :: proc "contextless" (wg: ^Wait_Group, duration: time.Duration) -> bool { if duration <= 0 { return false @@ -64,41 +111,43 @@ wait_group_wait_with_timeout :: proc "contextless" (wg: ^Wait_Group, duration: t return true } - - /* -A barrier enabling multiple threads to synchronize the beginning of some computation +Barrier. -Example: - package example +A barrier is a synchronization primitive enabling multiple threads to +synchronize the beginning of some computation. - import "core:fmt" - import "core:sync" - import "core:thread" +When `barrier_wait` procedure is called by any thread, that thread will block +the execution, until all threads associated with the barrier reach the same +point of execution and also call `barrier_wait`. - barrier := &sync.Barrier{} +when barrier is initialized, a `thread_count` parameter is passed, signifying +the amount of participant threads of the barrier. The barrier also keeps track +of an internal atomic counter. When a thread calls `barrier_wait`, the internal +counter is incremented. When the internal counter reaches `thread_count`, it is +reset and all threads waiting on the barrier are unblocked. - main :: proc "contextless" () { - fmt.println("Start") +This type of synchronization primitive can be used to synchronize "staged" +workloads, where the workload is split into stages, and until all threads have +completed the previous threads, no thread is allowed to start work on the next +stage. In this case, after each stage, a `barrier_wait` shall be inserted in the +thread procedure. - THREAD_COUNT :: 4 - threads: [THREAD_COUNT]^thread.Thread +**Example**: - sync.barrier_init(barrier, THREAD_COUNT) - - for _, i in threads { - threads[i] = thread.create_and_start(proc(t: ^thread.Thread) { - // Same messages will be printed together but without any interleaving - fmt.println("Getting ready!") - sync.barrier_wait(barrier) - fmt.println("Off their marks they go!") - }) - } - - for t in threads { - thread.destroy(t) // join and free thread - } - fmt.println("Finished") + THREAD_COUNT :: 4 + threads: [THREAD_COUNT]^thread.Thread + sync.barrier_init(barrier, THREAD_COUNT) + for _, i in threads { + threads[i] = thread.create_and_start(proc(t: ^thread.Thread) { + // Same messages will be printed together but without any interleaving + fmt.println("Getting ready!") + sync.barrier_wait(barrier) + fmt.println("Off their marks they go!") + }) + } + for t in threads { + thread.destroy(t) } */ Barrier :: struct #no_copy { @@ -109,6 +158,13 @@ Barrier :: struct #no_copy { thread_count: int, } +/* +Initialize a barrier. + + +This procedure initializes the barrier for the specified amount of participant +threads. +*/ barrier_init :: proc "contextless" (b: ^Barrier, thread_count: int) { when ODIN_VALGRIND_SUPPORT { vg.helgrind_barrier_resize_pre(b, uint(thread_count)) @@ -118,8 +174,13 @@ barrier_init :: proc "contextless" (b: ^Barrier, thread_count: int) { b.thread_count = thread_count } -// Block the current thread until all threads have rendezvoused -// Barrier can be reused after all threads rendezvoused once, and can be used continuously +/* +Block the current thread until all threads have rendezvoused. + +This procedure blocks the execution of the current thread, until all threads +have reached the same point in the execution of the thread proc. Multiple calls +to `barrier_wait` are allowed within the thread procedure. +*/ barrier_wait :: proc "contextless" (b: ^Barrier) -> (is_leader: bool) { when ODIN_VALGRIND_SUPPORT { vg.helgrind_barrier_wait_pre(b) @@ -140,15 +201,31 @@ barrier_wait :: proc "contextless" (b: ^Barrier) -> (is_leader: bool) { return true } +/* +Auto-reset event. +Represents a thread synchronization primitive that, when signalled, releases one +single waiting thread and then resets automatically to a state where it can be +signalled again. + +When a thread calls `auto_reset_event_wait`, it's execution will be blocked, +until the event is signalled by another thread. The call to +`auto_reset_event_signal` wakes up exactly one thread waiting for the event. +*/ Auto_Reset_Event :: struct #no_copy { // status == 0: Event is reset and no threads are waiting - // status == 1: Event is signaled + // status == 1: Event is signalled // status == -N: Event is reset and N threads are waiting status: i32, sema: Sema, } +/* +Signal an auto-reset event. + +This procedure signals an auto-reset event, waking up exactly one waiting +thread. +*/ auto_reset_event_signal :: proc "contextless" (e: ^Auto_Reset_Event) { old_status := atomic_load_explicit(&e.status, .Relaxed) for { @@ -163,6 +240,12 @@ auto_reset_event_signal :: proc "contextless" (e: ^Auto_Reset_Event) { } } +/* +Wait on an auto-reset event. + +This procedure blocks the execution of the current thread, until the event is +signalled by another thread. +*/ auto_reset_event_wait :: proc "contextless" (e: ^Auto_Reset_Event) { old_status := atomic_sub_explicit(&e.status, 1, .Acquire) if old_status < 1 { @@ -170,13 +253,35 @@ auto_reset_event_wait :: proc "contextless" (e: ^Auto_Reset_Event) { } } +/* +Ticket lock. +A ticket lock is a mutual exclusion lock that uses "tickets" to control which +thread is allowed into a critical section. +This synchronization primitive works just like spinlock, except that it implements +a "fairness" guarantee, making sure that each thread gets a roughly equal amount +of entries into the critical section. + +This type of synchronization primitive is applicable for short critical sections +in low-contention systems, as it uses a spinlock under the hood. +*/ Ticket_Mutex :: struct #no_copy { ticket: uint, serving: uint, } +/* +Acquire a lock on a ticket mutex. + +This procedure acquires a lock on a ticket mutex. If the ticket mutex is held +by another thread, this procedure also blocks the execution until the lock +can be acquired. + +Once the lock is acquired, any thread calling `ticket_mutex_lock` will be +blocked from entering any critical sections associated with the same ticket +mutex, until the lock is released. +*/ ticket_mutex_lock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) { ticket := atomic_add_explicit(&m.ticket, 1, .Relaxed) for ticket != atomic_load_explicit(&m.serving, .Acquire) { @@ -184,44 +289,147 @@ ticket_mutex_lock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) { } } +/* +Release a lock on a ticket mutex. + +This procedure releases the lock on a ticket mutex. If any of the threads are +waiting to acquire the lock, exactly one of those threads is unblocked and +allowed into the critical section. +*/ ticket_mutex_unlock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) { atomic_add_explicit(&m.serving, 1, .Relaxed) } + +/* +Guard the current scope with a lock on a ticket mutex. + +This procedure acquires a lock on a ticket mutex. The lock is automatically +released at the end of callee's scope. If the mutex was already locked, this +procedure also blocks until the lock can be acquired. + +When a lock has been acquired, all threads attempting to acquire a lock will be +blocked from entering any critical sections associated with the ticket mutex, +until the lock is released. + +This procedure always returns `true`. This makes it easy to define a critical +section by putting the function inside the `if` statement. + +**Example**: + + if ticket_mutex_guard(&m) { + ... + } +*/ @(deferred_in=ticket_mutex_unlock) ticket_mutex_guard :: proc "contextless" (m: ^Ticket_Mutex) -> bool { ticket_mutex_lock(m) return true } +/* +Benaphore. +A benaphore is a combination of an atomic variable and a semaphore that can +improve locking efficiency in a no-contention system. Acquiring a benaphore +lock doesn't call into an internal semaphore, if no other thread in a middle of +a critical section. + +Once a lock on a benaphore is acquired by a thread, no other thread is allowed +into any critical sections, associted with the same benaphore, until the lock +is released. +*/ Benaphore :: struct #no_copy { counter: i32, sema: Sema, } +/* +Acquire a lock on a benaphore. + +This procedure acquires a lock on the specified benaphore. If the lock on a +benaphore is already held, this procedure also blocks the execution of the +current thread, until the lock could be acquired. + +Once a lock is acquired, all threads attempting to take a lock will be blocked +from entering any critical sections associated with the same benaphore, until +until the lock is released. +*/ benaphore_lock :: proc "contextless" (b: ^Benaphore) { if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 { sema_wait(&b.sema) } } +/* +Try to acquire a lock on a benaphore. + +This procedure tries to acquire a lock on the specified benaphore. If it was +already locked, then the returned value is `false`, otherwise the lock is +acquired and the procedure returns `true`. + +If the lock is acquired, all threads that attempt to acquire a lock will be +blocked from entering any critical sections associated with the same benaphore, +until the lock is released. +*/ benaphore_try_lock :: proc "contextless" (b: ^Benaphore) -> bool { v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire) return v == 0 } +/* +Release a lock on a benaphore. + +This procedure releases a lock on the specified benaphore. If any of the threads +are waiting on the lock, exactly one thread is allowed into a critical section +associated with the same banaphore. +*/ benaphore_unlock :: proc "contextless" (b: ^Benaphore) { if atomic_sub_explicit(&b.counter, 1, .Release) > 0 { sema_post(&b.sema) } } +/* +Guard the current scope with a lock on a benaphore. + +This procedure acquires a lock on a benaphore. The lock is automatically +released at the end of callee's scope. If the benaphore was already locked, this +procedure also blocks until the lock can be acquired. + +When a lock has been acquired, all threads attempting to acquire a lock will be +blocked from entering any critical sections associated with the same benaphore, +until the lock is released. + +This procedure always returns `true`. This makes it easy to define a critical +section by putting the function inside the `if` statement. + +**Example**: + + if benaphore_guard(&m) { + ... + } +*/ @(deferred_in=benaphore_unlock) benaphore_guard :: proc "contextless" (m: ^Benaphore) -> bool { benaphore_lock(m) return true } +/* +Recursive benaphore. + +Recurisve benaphore is just like a plain benaphore, except it allows reentrancy +into the critical section. + +When a lock is acquired on a benaphore, all other threads attempting to +acquire a lock on the same benaphore will be blocked from any critical sections, +associated with the same benaphore. + +When a lock is acquired on a benaphore by a thread, that thread is allowed +to acquire another lock on the same benaphore. When a thread has acquired the +lock on a benaphore, the benaphore will stay locked until the thread releases +the lock as many times as it has been locked by the thread. +*/ Recursive_Benaphore :: struct #no_copy { counter: int, owner: int, @@ -229,6 +437,16 @@ Recursive_Benaphore :: struct #no_copy { sema: Sema, } +/* +Acquire a lock on a recursive benaphore. + +This procedure acquires a lock on a recursive benaphore. If the benaphore is +held by another thread, this function blocks until the lock can be acquired. + +Once a lock is acquired, all other threads attempting to acquire a lock will +be blocked from entering any critical sections associated with the same +recursive benaphore, until the lock is released. +*/ recursive_benaphore_lock :: proc "contextless" (b: ^Recursive_Benaphore) { tid := current_thread_id() if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 { @@ -241,6 +459,17 @@ recursive_benaphore_lock :: proc "contextless" (b: ^Recursive_Benaphore) { b.recursion += 1 } +/* +Try to acquire a lock on a recursive benaphore. + +This procedure attempts to acquire a lock on recursive benaphore. If the +benaphore is already held by a different thread, this procedure returns `false`. +Otherwise the lock is acquired and the procedure returns `true`. + +If the lock is acquired, all other threads attempting to acquire a lock will +be blocked from entering any critical sections assciated with the same recursive +benaphore, until the lock is released. +*/ recursive_benaphore_try_lock :: proc "contextless" (b: ^Recursive_Benaphore) -> bool { tid := current_thread_id() if b.owner == tid { @@ -256,6 +485,13 @@ recursive_benaphore_try_lock :: proc "contextless" (b: ^Recursive_Benaphore) -> return true } +/* +Release a lock on a recursive benaphore. + +This procedure releases a lock on the specified recursive benaphore. It also +causes the critical sections associated with the same benaphore, to become open +for other threads for entering. +*/ recursive_benaphore_unlock :: proc "contextless" (b: ^Recursive_Benaphore) { tid := current_thread_id() _assert(tid == b.owner, "tid != b.owner") @@ -272,24 +508,50 @@ recursive_benaphore_unlock :: proc "contextless" (b: ^Recursive_Benaphore) { // outside the lock } +/* +Guard the current scope with a recursive benaphore. + +This procedure acquires a lock on the specified recursive benaphores and +automatically releases it at the end of the callee's scope. If the recursive +benaphore was already held by a another thread, this procedure also blocks until +the lock can be acquired. + +When the lock is acquired all other threads attempting to take a lock will be +blocked from entering any critical sections associated with the same benaphore, +until the lock is released. + +This procedure always returns `true`, which makes it easy to define a critical +section by calling this procedure inside an `if` statement. + +**Example**: + + if recursive_benaphore_guard(&m) { + ... + } +*/ @(deferred_in=recursive_benaphore_unlock) recursive_benaphore_guard :: proc "contextless" (m: ^Recursive_Benaphore) -> bool { recursive_benaphore_lock(m) return true } +/* +Once action. - - -// Once is a data value that will perform exactly on action. -// -// A Once must not be copied after first use. +`Once` a synchronization primitive, that only allows a single entry into a +critical section from a single thread. +*/ Once :: struct #no_copy { m: Mutex, done: bool, } -// once_do calls the procedure fn if and only if once_do is being called for the first for this instance of Once. +/* +Call a function once. + +The `once_do` procedure group calls a specified function, if it wasn't already +called from the perspective of a specific `Once` struct. +*/ once_do :: proc{ once_do_without_data, once_do_without_data_contextless, @@ -297,7 +559,9 @@ once_do :: proc{ once_do_with_data_contextless, } -// once_do_without_data calls the procedure fn if and only if once_do_without_data is being called for the first for this instance of Once. +/* +Call a function with no data once. +*/ once_do_without_data :: proc(o: ^Once, fn: proc()) { @(cold) do_slow :: proc(o: ^Once, fn: proc()) { @@ -313,7 +577,9 @@ once_do_without_data :: proc(o: ^Once, fn: proc()) { } } -// once_do_without_data calls the procedure fn if and only if once_do_without_data is being called for the first for this instance of Once. +/* +Call a contextless function with no data once. +*/ once_do_without_data_contextless :: proc(o: ^Once, fn: proc "contextless" ()) { @(cold) do_slow :: proc(o: ^Once, fn: proc "contextless" ()) { @@ -329,7 +595,9 @@ once_do_without_data_contextless :: proc(o: ^Once, fn: proc "contextless" ()) { } } -// once_do_with_data calls the procedure fn if and only if once_do_with_data is being called for the first for this instance of Once. +/* +Call a function with data once. +*/ once_do_with_data :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr) { @(cold) do_slow :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr) { @@ -345,7 +613,9 @@ once_do_with_data :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr) { } } -// once_do_with_data_contextless calls the procedure fn if and only if once_do_with_data_contextless is being called for the first for this instance of Once. +/* +Call a contextless function with data once. +*/ once_do_with_data_contextless :: proc "contextless" (o: ^Once, fn: proc "contextless" (data: rawptr), data: rawptr) { @(cold) do_slow :: proc "contextless" (o: ^Once, fn: proc "contextless" (data: rawptr), data: rawptr) { @@ -361,83 +631,112 @@ once_do_with_data_contextless :: proc "contextless" (o: ^Once, fn: proc "context } } +/* +A Parker is an associated token which is initially not present: - - - -// A Parker is an associated token which is initially not present: -// * The `park` procedure blocks the current thread unless or until the token -// is available, at which point the token is consumed. -// * The `park_with_timeout` procedures works the same as `park` but only -// blocks for the specified duration. -// * The `unpark` procedure automatically makes the token available if it -// was not already. +* The `park` procedure blocks the current thread unless or until the token + is available, at which point the token is consumed. +* The `park_with_timeout` procedures works the same as `park` but only + blocks for the specified duration. +* The `unpark` procedure automatically makes the token available if it + was not already. +*/ Parker :: struct #no_copy { state: Futex, } -// Blocks the current thread until the token is made available. -// -// Assumes this is only called by the thread that owns the Parker. +@(private="file") PARKER_EMPTY :: 0 +@(private="file") PARKER_NOTIFIED :: 1 +@(private="file") PARKER_PARKED :: max(u32) + +/* +Blocks until the token is available. + +This procedure blocks the execution of the current thread, until a token is +made available. + +**Note**: This procedure assumes this is only called by the thread that owns +the Parker. +*/ park :: proc "contextless" (p: ^Parker) { - EMPTY :: 0 - NOTIFIED :: 1 - PARKED :: max(u32) - if atomic_sub_explicit(&p.state, 1, .Acquire) == NOTIFIED { + if atomic_sub_explicit(&p.state, 1, .Acquire) == PARKER_NOTIFIED { return } for { - futex_wait(&p.state, PARKED) - if _, ok := atomic_compare_exchange_strong_explicit(&p.state, NOTIFIED, EMPTY, .Acquire, .Acquire); ok { + futex_wait(&p.state, PARKER_PARKED) + if _, ok := atomic_compare_exchange_strong_explicit(&p.state, PARKER_NOTIFIED, PARKER_EMPTY, .Acquire, .Acquire); ok { return } } } -// Blocks the current thread until the token is made available, but only -// for a limited duration. -// -// Assumes this is only called by the thread that owns the Parker +/* +Blocks until the token is available with timeout. + +This procedure blocks the execution of the current thread until a token is made +available, or until the timeout has expired, whatever happens first. + +**Note**: This procedure assumes this is only called by the thread that owns +the Parker. +*/ park_with_timeout :: proc "contextless" (p: ^Parker, duration: time.Duration) { - EMPTY :: 0 - NOTIFIED :: 1 - PARKED :: max(u32) - if atomic_sub_explicit(&p.state, 1, .Acquire) == NOTIFIED { + start_tick := time.tick_now() + remaining_duration := duration + if atomic_sub_explicit(&p.state, 1, .Acquire) == PARKER_NOTIFIED { return } - futex_wait_with_timeout(&p.state, PARKED, duration) - atomic_exchange_explicit(&p.state, EMPTY, .Acquire) + for { + if !futex_wait_with_timeout(&p.state, PARKER_PARKED, remaining_duration) { + return + } + old, ok := atomic_compare_exchange_weak_explicit((^u32)(&p.state), PARKER_PARKED, PARKER_EMPTY, .Acquire, .Relaxed) + if ok || old == PARKER_PARKED { + return + } + end_tick := time.tick_now() + remaining_duration -= time.tick_diff(start_tick, end_tick) + start_tick = end_tick + } } -// Automatically makes thee token available if it was not already. +/* +Make the token available. +*/ unpark :: proc "contextless" (p: ^Parker) { - EMPTY :: 0 - NOTIFIED :: 1 - PARKED :: max(Futex) - if atomic_exchange_explicit(&p.state, NOTIFIED, .Release) == PARKED { + if atomic_exchange_explicit((^u32)(&p.state), PARKER_NOTIFIED, .Release) == PARKER_PARKED { futex_signal(&p.state) } } +/* +One-shot event. +A one-shot event is an associated token which is initially not present: -// A One_Shot_Event is an associated token which is initially not present: -// * The `one_shot_event_wait` blocks the current thread until the event -// is made available -// * The `one_shot_event_signal` procedure automatically makes the token -// available if its was not already. +* The `one_shot_event_wait` blocks the current thread until the event + is made available +* The `one_shot_event_signal` procedure automatically makes the token + available if its was not already. +*/ One_Shot_Event :: struct #no_copy { state: Futex, } -// Blocks the current thread until the event is made available with `one_shot_event_signal`. +/* +Block until the event is made available. + +This procedure blocks the execution of the current thread, until the event is +made available. +*/ one_shot_event_wait :: proc "contextless" (e: ^One_Shot_Event) { for atomic_load_explicit(&e.state, .Acquire) == 0 { futex_wait(&e.state, 0) } } -// Releases any threads that are currently blocked by this event with `one_shot_event_wait`. +/* +Make event available. +*/ one_shot_event_signal :: proc "contextless" (e: ^One_Shot_Event) { atomic_store_explicit(&e.state, 1, .Release) futex_broadcast(&e.state) diff --git a/core/sync/primitives.odin b/core/sync/primitives.odin index 8fa3dd232..a22824481 100644 --- a/core/sync/primitives.odin +++ b/core/sync/primitives.odin @@ -3,46 +3,108 @@ package sync import "base:runtime" import "core:time" +/* +Obtain the current thread ID. +*/ current_thread_id :: proc "contextless" () -> int { return _current_thread_id() } -// A Mutex is a [[mutual exclusion lock; https://en.wikipedia.org/wiki/Mutual_exclusion]] -// It can be used to prevent more than one thread from executing the same piece of code, -// and thus prevent access to same piece of memory by multiple threads, at the same time. -// -// A Mutex's zero value represents an initial, *unlocked* state. -// -// If another thread tries to take the lock while another thread holds it, it will pause -// until the lock is released. Code or memory that is "surrounded" by a mutex lock is said -// to be "guarded by a mutex". -// -// A Mutex must not be copied after first use (e.g., after locking it the first time). -// This is because, in order to coordinate with other threads, all threads must watch -// the same memory address to know when the lock has been released. Trying to use a -// copy of the lock at a different memory address will result in broken and unsafe -// behavior. For this reason, Mutexes are marked as `#no_copy`. +/* +Mutual exclusion lock. + +A Mutex is a [[mutual exclusion lock; https://en.wikipedia.org/wiki/Mutual_exclusion]] +It can be used to prevent more than one thread from entering the critical +section, and thus prevent access to same piece of memory by multiple threads, at +the same time. + +Mutex's zero-initializzed value represents an initial, *unlocked* state. + +If another thread tries to acquire the lock, while it's already held (typically +by another thread), the thread's execution will be blocked, until the lock is +released. Code or memory that is "surrounded" by a mutex lock and unlock +operations is said to be "guarded by a mutex". + +**Note**: A Mutex must not be copied after first use (e.g., after locking it the +first time). This is because, in order to coordinate with other threads, all +threads must watch the same memory address to know when the lock has been +released. Trying to use a copy of the lock at a different memory address will +result in broken and unsafe behavior. For this reason, Mutexes are marked as +`#no_copy`. + +**Note**: If the current thread attempts to lock a mutex, while it's already +holding another lock, that will cause a trivial case of deadlock. Do not use +`Mutex` in recursive functions. In case multiple locks by the same thread are +desired, use `Recursive_Mutex`. +*/ Mutex :: struct #no_copy { impl: _Mutex, } -// mutex_lock locks m +/* +Acquire a lock on a mutex. + +This procedure acquires a lock with the specified mutex. If the mutex has been +already locked by any thread, this procedure also blocks until the lock can be +acquired. + +Once the lock is acquired, all other threads that attempt to acquire a lock will +be blocked from entering any critical sections associated with the same mutex, +until the the lock is released. + +**Note**: If the mutex is already locked by the current thread, a call to this +procedure will block indefinately. Do not use this in recursive procedures. +*/ mutex_lock :: proc "contextless" (m: ^Mutex) { _mutex_lock(m) } -// mutex_unlock unlocks m +/* +Release a lock on a mutex. + +This procedure releases the lock associated with the specified mutex. If the +mutex was not locked, this operation is a no-op. + +When the current thread, that holds a lock to the mutex calls `mutex_unlock`, +this allows one other thread waiting on the mutex to enter any critical sections +associated with the mutex. If there are no threads waiting on the mutex, the +critical sections will remain open. +*/ mutex_unlock :: proc "contextless" (m: ^Mutex) { _mutex_unlock(m) } -// mutex_try_lock tries to lock m, will return true on success, and false on failure +/* +Try to acquire a lock on a mutex. + +This procedure tries to acquire a lock on the specified mutex. If it was already +locked, then the returned value is `false`, otherwise the lock is acquired and +the procedure returns `true`. + +If the lock is acquired, all threads that attempt to acquire a lock will be +blocked from entering any critical sections associated with the same mutex, +until the lock is released. +*/ mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool { return _mutex_try_lock(m) } /* -Example: +Guard the current scope with a lock on a mutex. + +This procedure acquires a mutex lock. The lock is automatically released +at the end of callee's scope. If the mutex was already locked, this procedure +also blocks until the lock can be acquired. + +When a lock has been acquired, all threads attempting to acquire a lock will be +blocked from entering any critical sections associated with the mutex, until +the lock is released. + +This procedure always returns `true`. This makes it easy to define a critical +section by putting the function inside the `if` statement. + +**Example**: + if mutex_guard(&m) { ... } @@ -53,47 +115,145 @@ mutex_guard :: proc "contextless" (m: ^Mutex) -> bool { return true } -// A RW_Mutex is a reader/writer mutual exclusion lock -// The lock can be held by any arbitrary number of readers or a single writer -// The zero value for a RW_Mutex is an unlocked mutex -// -// A RW_Mutex must not be copied after first use +/* +Read-write mutual exclusion lock. + +An `RW_Mutex` is a reader/writer mutual exclusion lock. The lock can be held by +any number of readers or a single writer. + +This type of synchronization primitive supports two kinds of lock operations: + +- Exclusive lock (write lock) +- Shared lock (read lock) + +When an exclusive lock is acquired by any thread, all other threads, attempting +to acquire either an exclusive or shared lock, will be blocked from entering the +critical sections associated with the read-write mutex, until the exclusive +owner of the lock releases the lock. + +When a shared lock is acquired by any thread, any other thread attempting to +acquire a shared lock will also be able to enter all the critical sections +associated with the read-write mutex. However threads attempting to acquire +an exclusive lock will be blocked from entering those critical sections, until +all shared locks are released. + +**Note**: A read-write mutex must not be copied after first use (e.g., after +acquiring a lock). This is because, in order to coordinate with other threads, +all threads must watch the same memory address to know when the lock has been +released. Trying to use a copy of the lock at a different memory address will +result in broken and unsafe behavior. For this reason, mutexes are marked as +`#no_copy`. + +**Note**: A read-write mutex is not recursive. Do not attempt to acquire an +exclusive lock more than once from the same thread, or an exclusive and shared +lock on the same thread. Taking a shared lock multiple times is acceptable. +*/ RW_Mutex :: struct #no_copy { impl: _RW_Mutex, } -// rw_mutex_lock locks rw for writing (with a single writer) -// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available. +/* +Acquire an exclusive lock. + +This procedure acquires an exclusive lock on the specified read-write mutex. If +the lock is already held by any thread, this procedure also blocks until the +lock can be acquired. + +After a lock has been acquired, any thread attempting to acquire any lock +will be blocked from entering any critical sections associated with the same +read-write mutex, until the exclusive lock is released. +*/ rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) { _rw_mutex_lock(rw) } -// rw_mutex_unlock unlocks rw for writing (with a single writer) +/* +Release an exclusive lock. + +This procedure releases an exclusive lock associated with the specified +read-write mutex. + +When the exclusive lock is released, all critical sections, associated with the +same read-write mutex, become open to other threads. +*/ rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) { _rw_mutex_unlock(rw) } -// rw_mutex_try_lock tries to lock rw for writing (with a single writer) +/* +Try to acquire an exclusive lock on a read-write mutex. + +This procedure tries to acquire an exclusive lock on the specified read-write +mutex. If the mutex was already locked, the procedure returns `false`. Otherwise +it acquires the exclusive lock and returns `true`. + +If the lock has been acquired, all threads attempting to acquire any lock +will be blocked from entering any critical sections associated with the same +read-write mutex, until the exclusive locked is released. +*/ rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool { return _rw_mutex_try_lock(rw) } -// rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers) +/* +Acquire a shared lock on a read-write mutex. + +This procedure acquires a shared lock on the specified read-write mutex. If the +mutex already has an exclusive lock held, this procedure also blocks until the +lock can be acquired. + +After the shared lock is obtained, all threads attempting to acquire an +exclusive lock will be blocked from entering any critical sections associated +with the same read-write mutex, until all shared locks associated with the +specified read-write mutex are released. +*/ rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) { _rw_mutex_shared_lock(rw) } -// rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers) +/* +Release the shared lock on a read-write mutex. + +This procedure releases shared lock on the specified read-write mutex. When all +shared locks are released, all critical sections associated with the same +read-write mutex become open to other threads. +*/ rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) { _rw_mutex_shared_unlock(rw) } -// rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers) +/* +Try to acquire a shared lock on a read-write mutex. + +This procedure attempts to acquire a lock on the specified read-write mutex. If +the mutex already has an exclusive lock held, this procedure returns `false`. +Otherwise, it acquires the lock on the mutex and returns `true`. + +If the shared lock has been acquired, it causes all threads attempting to +acquire the exclusive lock to be blocked from entering any critical sections +associated with the same read-write mutex, until all shared locks are released. +*/ rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool { return _rw_mutex_try_shared_lock(rw) } + /* -Example: +Guard the current scope with an exclusive lock on a read-write mutex. + +This procedure acquires an exclusive lock on the specified read-write mutex. +This procedure automatically releases the lock at the end of the callee's scope. +If the mutex was already locked by readers or a writer, this procedure blocks, +until a lock can be acquired. + +When an exclusive lock is acquired, all other threads attempting to acquire an +exclusive lock will be blocked from entering any critical sections associated +with the same read-write mutex, until the exclusive lock is released. + +This procedure always returns `true`, which makes it easy to define a critical +section by running this procedure inside an `if` statement. + +**Example**: + if rw_mutex_guard(&m) { ... } @@ -105,8 +265,23 @@ rw_mutex_guard :: proc "contextless" (m: ^RW_Mutex) -> bool { } /* -Example: - if rw_mutex_shared_guard(&m) { +Guard the current scope with a shared lock on a read-write mutex. + +This procedure acquires a shared lock on the specified read-write mutex. This +procedure automatically releases the lock at the end of the callee's scope. If +the mutex already has an associated exclusive lock, this procedure blocks, until +a lock can be acquired. + +When a shared lock is obtained, all other threads attempting to obtain an +exclusive lock will be blocked from any critical sections, associated with the +same read-write mutex, until all shared locks are released. + +This procedure always returns `true`, which makes it easy to define a critical +section by running this procedure inside an `if` statement. + +**Example**: + + if rw_mutex_guard(&m) { ... } */ @@ -116,30 +291,91 @@ rw_mutex_shared_guard :: proc "contextless" (m: ^RW_Mutex) -> bool { return true } +/* +Recursive mutual exclusion lock. +Recurisve mutex is just like a plain mutex, except it allows reentrancy. In +order for a thread to release the mutex for other threads, the mutex needs to +be unlocked as many times, as it was locked. -// A Recursive_Mutex is a recursive mutual exclusion lock -// The zero value for a Recursive_Mutex is an unlocked mutex -// -// A Recursive_Mutex must not be copied after first use +When a lock is acquired on a recursive mutex, all other threads attempting to +acquire a lock on the same mutex will be blocked from any critical sections, +associated with the same recrusive mutex. + +When a lock is acquired on a recursive mutex by a thread, that thread is allowed +to acquire another lock on the same mutex. When a thread has acquired the lock +on a recursive mutex, the recursive mutex will stay locked until the thread +releases the lock as many times as it has been locked by the thread. + +**Note**: A recursive mutex must not be copied after first use (e.g., after +acquiring a lock). This is because, in order to coordinate with other threads, +all threads must watch the same memory address to know when the lock has been +released. Trying to use a copy of the lock at a different memory address will +result in broken and unsafe behavior. For this reason, mutexes are marked as +`#no_copy`. +*/ Recursive_Mutex :: struct #no_copy { impl: _Recursive_Mutex, } +/* +Acquire a lock on a recursive mutex. + +This procedure acquires a lock on the specified recursive mutex. If the lock is +acquired by a different thread, this procedure also blocks until the lock can be +acquired. + +When the lock is acquired, all other threads attempting to acquire a lock will +be blocked from entering any critical sections associated with the same mutex, +until the lock is released. +*/ recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) { _recursive_mutex_lock(m) } +/* +Release a lock on a recursive mutex. + +This procedure releases a lock on the specified recursive mutex. It also causes +the critical sections associated with the same mutex, to become open for other +threads for entering. +*/ recursive_mutex_unlock :: proc "contextless" (m: ^Recursive_Mutex) { _recursive_mutex_unlock(m) } +/* +Try to acquire a lock on a recursive mutex. + +This procedure attempts to acquire a lock on the specified recursive mutex. If +the recursive mutex is locked by other threads, this procedure returns `false`. +Otherwise it locks the mutex and returns `true`. + +If the lock is acquired, all other threads attempting to obtain a lock will be +blocked from entering any critical sections associated with the same mutex, +until the lock is released. +*/ recursive_mutex_try_lock :: proc "contextless" (m: ^Recursive_Mutex) -> bool { return _recursive_mutex_try_lock(m) } /* -Example: +Guard the scope with a recursive mutex lock. + +This procedure acquires a lock on the specified recursive mutex and +automatically releases it at the end of the callee's scope. If the recursive +mutex was already held by a another thread, this procedure also blocks until the +lock can be acquired. + +When the lock is acquired all other threads attempting to take a lock will be +blocked from entering any critical sections associated with the same mutex, +until the lock is released. + +This procedure always returns `true`, which makes it easy to define a critical +section by calling this procedure inside an `if` statement. + +**Example**: + if recursive_mutex_guard(&m) { ... } @@ -150,19 +386,69 @@ recursive_mutex_guard :: proc "contextless" (m: ^Recursive_Mutex) -> bool { return true } +/* +A condition variable. -// Cond implements a condition variable, a rendezvous point for threads -// waiting for signalling the occurence of an event -// -// A Cond must not be copied after first use +`Cond` implements a condition variable, a rendezvous point for threads waiting +for signalling the occurence of an event. Condition variables are used on +conjuction with mutexes to provide a shared access to one or more shared +variable. + +A typical usage of condition variable is as follows. A thread that intends to +modify a shared variable shall: + +1. Acquire a lock on a mutex. +2. Modify the shared memory. +3. Release the lock. +3. Call `cond_signal` or `cond_broadcast`. + +A thread that intends to wait on a shared variable shall: + +1. Acquire a lock on a mutex. +2. Call `cond_wait` or `cond_wait_with_timeout` (will release the mutex). +3. Check the condition and keep waiting in a loop if not satisfied with result. + +**Note**: A condition variable must not be copied after first use (e.g., after +waiting on it the first time). This is because, in order to coordinate with +other threads, all threads must watch the same memory address to know when the +lock has been released. Trying to use a copy of the lock at a different memory +address will result in broken and unsafe behavior. For this reason, condition +variables are marked as `#no_copy`. +*/ Cond :: struct #no_copy { impl: _Cond, } +/* +Wait until the condition variable is signalled and release the associated mutex. + +This procedure blocks the current thread until the specified condition variable +is signalled, or until a spurious wakeup occurs. In addition, if the condition +has been signalled, this procedure releases the lock on the specified mutex. + +The mutex must be held by the calling thread, before calling the procedure. + +**Note**: This procedure can return on a spurious wake-up, even if the condition +variable was not signalled by a thread. +*/ cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) { _cond_wait(c, m) } +/* +Wait until the condition variable is signalled or timeout is reached and release +the associated mutex. + +This procedure blocks the current thread until the specified condition variable +is signalled, a timeout is reached, or until a spurious wakeup occurs. In +addition, if the condition has been signalled, this procedure releases the +lock on the specified mutex. + +If the timeout was reached, this procedure returns `false`. Otherwise it returns +`true`. + +Before this procedure is called the mutex must be held by the calling thread. +*/ cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { if duration <= 0 { return false @@ -170,51 +456,123 @@ cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: tim return _cond_wait_with_timeout(c, m, duration) } +/* +Wake up one thread that waits on a condition variable. + +This procedure causes exactly one thread waiting on the condition variable to +wake up. +*/ cond_signal :: proc "contextless" (c: ^Cond) { _cond_signal(c) } +/* +Wake up all threads that wait on a condition variable. + +This procedure causes all threads waiting on the condition variable to wake up. +*/ cond_broadcast :: proc "contextless" (c: ^Cond) { _cond_broadcast(c) } +/* +Semaphore. -// When waited upon, blocks until the internal count is greater than zero, then subtracts one. -// Posting to the semaphore increases the count by one, or the provided amount. -// -// A Sema must not be copied after first use +When waited upon, semaphore blocks until the internal count is greater than +zero, then decrements the internal counter by one. Posting to the semaphore +increases the count by one, or the provided amount. + +This type of synchronization primitives can be useful for implementing queues. +The internal counter of the semaphore can be thought of as the amount of items +in the queue. After a data has been pushed to the queue, the thread shall call +`sema_post()` procedure, increasing the counter. When a thread takes an item +from the queue to do the job, it shall call `sema_wait()`, waiting on the +semaphore counter to become non-zero and decreasing it, if necessary. + +**Note**: A semaphore must not be copied after first use (e.g., after posting +to it). This is because, in order to coordinate with other threads, all threads +must watch the same memory address to know when the lock has been released. +Trying to use a copy of the lock at a different memory address will result in +broken and unsafe behavior. For this reason, semaphores are marked as `#no_copy`. +*/ Sema :: struct #no_copy { impl: _Sema, } +/* +Increment the internal counter on a semaphore by the specified amount. + +This procedure increments the internal counter of the semaphore. If any of the +threads were waiting on the semaphore, up to `count` of threads will continue +the execution and enter the critical section. +*/ sema_post :: proc "contextless" (s: ^Sema, count := 1) { _sema_post(s, count) } +/* +Wait on a semaphore until the internal counter is non-zero. + +This procedure blocks the execution of the current thread, until the semaphore +counter is non-zero, and atomically decrements it by one, once the wait has +ended. +*/ sema_wait :: proc "contextless" (s: ^Sema) { _sema_wait(s) } +/* +Wait on a semaphore until the internal counter is non-zero or a timeout is reached. + +This procedure blocks the execution of the current thread, until the semaphore +counter is non-zero, and if so atomically decrements it by one, once the wait +has ended. If the specified timeout is reached, the function returns `false`, +otherwise it returns `true`. +*/ sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool { return _sema_wait_with_timeout(s, duration) } +/* +Fast userspace mutual exclusion lock. +Futex is a fast userspace mutual exclusion lock, that uses a pointer to a 32-bit +value as an identifier of the queue of waiting threads. The value pointed to +by that pointer can be used to store extra data. -// Futex is a fast userspace mutual exclusion lock, using a 32-bit memory address as a hint -// -// An Futex must not be copied after first use +**IMPORTANT**: A futex must not be copied after first use (e.g., after waiting +on it the first time, or signalling it). This is because, in order to coordinate +with other threads, all threads must watch the same memory address. Trying to +use a copy of the lock at a different memory address will result in broken and +unsafe behavior. +*/ Futex :: distinct u32 +/* +Sleep if the futex contains the expected value until it's signalled. + +If the value of the futex is `expected`, this procedure blocks the execution of +the current thread, until the futex is woken up, or until a spurious wakeup +occurs. +*/ futex_wait :: proc "contextless" (f: ^Futex, expected: u32) { if u32(atomic_load_explicit(f, .Acquire)) != expected { return } - - _assert(_futex_wait(f, expected), "futex_wait failure") + ok := _futex_wait(f, expected) + _assert(ok, "futex_wait failure") } -// returns true if the wait happened within the duration, false if it exceeded the time duration +/* +Sleep if the futex contains the expected value until it's signalled or the +timeout is reached. + +If the value of the futex is `expected`, this procedure blocks the execution of +the current thread, until the futex is signalled, a timeout is reached, or +until a spurious wakeup occurs. + +This procedure returns `false` if the timeout was reached, `true` otherwise. +*/ futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool { if u32(atomic_load_explicit(f, .Acquire)) != expected { return true @@ -226,10 +584,16 @@ futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duratio return _futex_wait_with_timeout(f, expected, duration) } +/* +Wake up a single thread waiting on a futex. +*/ futex_signal :: proc "contextless" (f: ^Futex) { _futex_signal(f) } +/* +Wake up multiple threads waiting on a futex. +*/ futex_broadcast :: proc "contextless" (f: ^Futex) { _futex_broadcast(f) } From 744d7f7ef420bfc747988ca52bdf202fbdc03807 Mon Sep 17 00:00:00 2001 From: Thomas la Cour Date: Tue, 30 Jul 2024 16:53:14 +0200 Subject: [PATCH 036/122] fix for using .rc files --- src/build_settings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 49bb83b22..faa8ad2b6 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1822,6 +1822,7 @@ gb_internal bool init_build_paths(String init_filename) { if (bc->resource_filepath.len > 0) { bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath); if (!string_ends_with(bc->resource_filepath, str_lit(".res"))) { + bc->build_paths[BuildPath_RES].ext = copy_string(ha, STR_LIT("res")); bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath); bc->build_paths[BuildPath_RC].ext = copy_string(ha, STR_LIT("rc")); } From 1913c08b7bc5017f1abb771590782d0b63a7cfbe Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Tue, 30 Jul 2024 18:09:51 +0200 Subject: [PATCH 037/122] [os2] Add missing temp_file implementation for Linux --- core/os/os2/temp_file_linux.odin | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/os/os2/temp_file_linux.odin b/core/os/os2/temp_file_linux.odin index 92afcde47..d6f90fbaf 100644 --- a/core/os/os2/temp_file_linux.odin +++ b/core/os/os2/temp_file_linux.odin @@ -3,8 +3,11 @@ package os2 import "base:runtime" - -_temp_dir :: proc(allocator: runtime.Allocator) -> (string, Error) { - //TODO - return "", nil +_temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { + TEMP_ALLOCATOR_GUARD() + tmpdir := get_env("TMPDIR", temp_allocator()) + if tmpdir == "" { + tmpdir = "/tmp" + } + return clone_string(tmpdir, allocator) } From f33b4ecd3ee04d3f42e754574ebcd42e8c4ef572 Mon Sep 17 00:00:00 2001 From: Alex Macafee Date: Wed, 31 Jul 2024 18:48:16 +1000 Subject: [PATCH 038/122] Update Raygui Style set/get functions --- vendor/raylib/raygui.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/raylib/raygui.odin b/vendor/raylib/raygui.odin index 8cda9c072..8a9d4d7cd 100644 --- a/vendor/raylib/raygui.odin +++ b/vendor/raylib/raygui.odin @@ -236,8 +236,8 @@ foreign lib { // Style set/get functions - GuiSetStyle :: proc(control: GuiControl, property: GuiStyleProp, value: c.int) --- // Set one style property - GuiGetStyle :: proc(control: GuiControl, property: GuiStyleProp) -> c.int --- // Get one style property + GuiSetStyle :: proc(control: GuiControl, property: c.int, value: c.int) --- // Set one style property + GuiGetStyle :: proc(control: GuiControl, property: c.int) -> c.int --- // Get one style property // Styles loading functions From 92831d7ca3493d964e7883ba754d021ea5259612 Mon Sep 17 00:00:00 2001 From: Alex Macafee Date: Wed, 31 Jul 2024 18:58:43 +1000 Subject: [PATCH 039/122] Remove GuiStyleProp --- vendor/raylib/raygui.odin | 7 ------- 1 file changed, 7 deletions(-) diff --git a/vendor/raylib/raygui.odin b/vendor/raylib/raygui.odin index 8a9d4d7cd..cab18ff8e 100644 --- a/vendor/raylib/raygui.odin +++ b/vendor/raylib/raygui.odin @@ -28,13 +28,6 @@ when ODIN_OS == .Windows { RAYGUI_VERSION :: "4.0" -// Style property -GuiStyleProp :: struct { - controlId: u16, - propertyId: u16, - propertyValue: c.int, -} - // Gui control state GuiState :: enum c.int { STATE_NORMAL = 0, From 1f2ab84e828d058019d760f8a2549ca6158e4555 Mon Sep 17 00:00:00 2001 From: Alex Macafee Date: Wed, 31 Jul 2024 19:08:08 +1000 Subject: [PATCH 040/122] Use GuiControlProperty instead of c.int --- vendor/raylib/raygui.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/raylib/raygui.odin b/vendor/raylib/raygui.odin index cab18ff8e..bcbb364da 100644 --- a/vendor/raylib/raygui.odin +++ b/vendor/raylib/raygui.odin @@ -229,8 +229,8 @@ foreign lib { // Style set/get functions - GuiSetStyle :: proc(control: GuiControl, property: c.int, value: c.int) --- // Set one style property - GuiGetStyle :: proc(control: GuiControl, property: c.int) -> c.int --- // Get one style property + GuiSetStyle :: proc(control: GuiControl, property: GuiControlProperty, value: c.int) --- // Set one style property + GuiGetStyle :: proc(control: GuiControl, property: GuiControlProperty) -> c.int --- // Get one style property // Styles loading functions From fdfe6b00e0e8558050ebd6e6c7cb33b3d789be4f Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 31 Jul 2024 15:16:09 +0200 Subject: [PATCH 041/122] Improve output path checking Fixes #4001 --- src/build_settings.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index faa8ad2b6..3e2d11101 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -2011,15 +2011,20 @@ gb_internal bool init_build_paths(String init_filename) { } } + String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); + defer (gb_free(ha, output_file.text)); + // Check if output path is a directory. if (path_is_directory(bc->build_paths[BuildPath_Output])) { - String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); - defer (gb_free(ha, output_file.text)); gb_printf_err("Output path %.*s is a directory.\n", LIT(output_file)); return false; } - if (!write_directory(bc->build_paths[BuildPath_Output].basename)) { + gbFile output_file_test; + gbFileError output_test_err = gb_file_open_mode(&output_file_test, gbFileMode_Append | gbFileMode_Rw, (const char*)output_file.text); + defer (gb_file_close(&output_file_test)); + + if (output_test_err != 0) { String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); defer (gb_free(ha, output_file.text)); gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file)); From 953ae326071da383dc8d9a2e977de5b1868c2477 Mon Sep 17 00:00:00 2001 From: Damian Tarnawski Date: Wed, 31 Jul 2024 18:55:04 +0200 Subject: [PATCH 042/122] Update builtin constants --- base/runtime/core.odin | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 56aaefaa9..e2490051e 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -525,11 +525,12 @@ Raw_Quaternion256_Vector_Scalar :: struct {vector: [3]f64, scalar: f64} Linux, Essence, FreeBSD, - Haiku, OpenBSD, NetBSD, + Haiku, WASI, JS, + Orca, Freestanding, } */ @@ -589,7 +590,7 @@ Odin_Platform_Subtarget_Type :: type_of(ODIN_PLATFORM_SUBTARGET) Memory = 1, Thread = 2, } - Odin_Sanitizer_Flags :: distinct bitset[Odin_Sanitizer_Flag; u32] + Odin_Sanitizer_Flags :: distinct bit_set[Odin_Sanitizer_Flag; u32] ODIN_SANITIZER_FLAGS // is a constant */ From f627a38b4fb31416516144e7077abf389295d491 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 31 Jul 2024 20:00:55 +0200 Subject: [PATCH 043/122] Update rand.reset() example. --- core/math/rand/rand.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index e02f3db80..61301cf8a 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -58,7 +58,7 @@ Example: import "core:fmt" set_global_seed_example :: proc() { - rand.set_global_seed(1) + rand.reset(1) fmt.println(rand.uint64()) } From 0fa62937d58fe5bc014a2749f68aaac518f79e92 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 31 Jul 2024 20:19:13 +0200 Subject: [PATCH 044/122] Fix NetBSD CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73cd3493b..bdb94662f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: usesh: true copyback: false prepare: | - PKG_PATH="https://cdn.NetBSD.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$(uname -r | cut -d_ -f1)_${PKGSRC_BRANCH}/All" /usr/sbin/pkg_add pkgin + PKG_PATH="https://cdn.NetBSD.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/10.0_2024Q2/All" /usr/sbin/pkg_add pkgin pkgin -y in gmake git bash python311 llvm clang ln -s /usr/pkg/bin/python3.11 /usr/bin/python3 run: | From e7041f785acccf31c9b7af38051a10f748c06495 Mon Sep 17 00:00:00 2001 From: daniel-andersen Date: Fri, 2 Aug 2024 11:04:10 +0200 Subject: [PATCH 045/122] Quality of life changes to wgpu/wasm stuff --- vendor/wasm/js/events.odin | 2 ++ vendor/wgpu/wgpu.odin | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/vendor/wasm/js/events.odin b/vendor/wasm/js/events.odin index 2d3f01ceb..4e786e2be 100644 --- a/vendor/wasm/js/events.odin +++ b/vendor/wasm/js/events.odin @@ -33,6 +33,7 @@ Event_Kind :: enum u32 { Submit, Blur, Change, + HashChange, Select, Animation_Start, @@ -112,6 +113,7 @@ event_kind_string := [Event_Kind]string{ .Submit = "submit", .Blur = "blur", .Change = "change", + .HashChange = "hashchange", .Select = "select", .Animation_Start = "animationstart", diff --git a/vendor/wgpu/wgpu.odin b/vendor/wgpu/wgpu.odin index 4efe572cf..b486faf3a 100644 --- a/vendor/wgpu/wgpu.odin +++ b/vendor/wgpu/wgpu.odin @@ -716,12 +716,7 @@ BufferDescriptor :: struct { mappedAtCreation: b32, } -Color :: struct { - r: f64, - g: f64, - b: f64, - a: f64, -} +Color :: [4]f32 CommandBufferDescriptor :: struct { nextInChain: ^ChainedStruct, From 3bfccde6f9f8344d82def69f7a9c2745e486c433 Mon Sep 17 00:00:00 2001 From: marcosantos98 Date: Fri, 2 Aug 2024 10:50:16 +0100 Subject: [PATCH 046/122] Fix: remove extra `usage` in webgl.odin:250 Compilation error when using webgl.BufferSubDataSlice. The `usage` parameter is nowhere to be found. This is probably a copy-pasta leftover. --- vendor/wasm/WebGL/webgl.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/wasm/WebGL/webgl.odin b/vendor/wasm/WebGL/webgl.odin index 0ecfa8644..389e729de 100644 --- a/vendor/wasm/WebGL/webgl.odin +++ b/vendor/wasm/WebGL/webgl.odin @@ -247,7 +247,7 @@ BufferDataSlice :: proc "contextless" (target: Enum, slice: $S/[]$E, usage: Enum BufferData(target, len(slice)*size_of(E), raw_data(slice), usage) } BufferSubDataSlice :: proc "contextless" (target: Enum, offset: uintptr, slice: $S/[]$E) { - BufferSubData(target, offset, len(slice)*size_of(E), raw_data(slice), usage) + BufferSubData(target, offset, len(slice)*size_of(E), raw_data(slice)) } CompressedTexImage2DSlice :: proc "contextless" (target: Enum, level: i32, internalformat: Enum, width, height: i32, border: i32, slice: $S/[]$E) { From 723e6d19be3eaf710c93a32dd84abcae441536bf Mon Sep 17 00:00:00 2001 From: daniel-andersen Date: Fri, 2 Aug 2024 13:38:36 +0200 Subject: [PATCH 047/122] right number whoops! --- vendor/wgpu/wgpu.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/wgpu/wgpu.odin b/vendor/wgpu/wgpu.odin index b486faf3a..af81dde56 100644 --- a/vendor/wgpu/wgpu.odin +++ b/vendor/wgpu/wgpu.odin @@ -716,7 +716,7 @@ BufferDescriptor :: struct { mappedAtCreation: b32, } -Color :: [4]f32 +Color :: [4]f64 CommandBufferDescriptor :: struct { nextInChain: ^ChainedStruct, From 1a16585b10044255097e0abaa73aa4f0a422cbd1 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 2 Aug 2024 14:54:52 +0200 Subject: [PATCH 048/122] Add image.pixels_to_image helper. --- core/image/common.odin | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/core/image/common.odin b/core/image/common.odin index 2b1f71711..94321f644 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -112,7 +112,8 @@ Image_Option: `.alpha_drop_if_present` If the image has an alpha channel, drop it. - You may want to use `.alpha_premultiply` in this case. + You may want to use `.alpha_ + tiply` in this case. NOTE: For PNG, this also skips handling of the tRNS chunk, if present, unless you select `alpha_premultiply`. @@ -587,6 +588,32 @@ Channel :: enum u8 { A = 4, } +// Take a slice of pixels (`[]RGBA_Pixel`, etc), and return an `Image` +// Don't call `destroy` on the resulting `Image`. Instead, delete the original `pixels` slice. +pixels_to_image :: proc(pixels: [][$N]$E, width: int, height: int) -> (img: Image, ok: bool) where E == u8 || E == u16, N >= 1 && N <= 4 { + if len(pixels) != width * height { + return {}, false + } + + img.height = height + img.width = width + img.depth = 8 when E == u8 else 16 + img.channels = N + + s := transmute(runtime.Raw_Slice)pixels + d := runtime.Raw_Dynamic_Array{ + data = s.data, + len = s.len * size_of(E) * N, + cap = s.len * size_of(E) * N, + allocator = runtime.nil_allocator(), + } + img.pixels = bytes.Buffer{ + buf = transmute([dynamic]u8)d, + } + + return img, true +} + // When you have an RGB(A) image, but want a particular channel. return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok: bool) { // Were we actually given a valid image? From e55d09bdfac42a512863342193b68de508f26c51 Mon Sep 17 00:00:00 2001 From: Emir <60936780+elvodqa@users.noreply.github.com> Date: Fri, 2 Aug 2024 18:04:36 +0300 Subject: [PATCH 049/122] Update vendor/wgpu/examples/sdl2/main.odin Co-authored-by: Laytan --- vendor/wgpu/examples/sdl2/main.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/wgpu/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin index 646f04c40..3d79346d0 100644 --- a/vendor/wgpu/examples/sdl2/main.odin +++ b/vendor/wgpu/examples/sdl2/main.odin @@ -53,7 +53,7 @@ main :: proc() { } state.device = device - width, height : u32 = 800, 600 // os_get_render_bounds(&state.os) + width, height := os_get_render_bounds(&state.os) state.config = wgpu.SurfaceConfiguration { device = state.device, From 99d9e8f8b1028c4208e2788f77044d2e1d2a8667 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 3 Aug 2024 00:21:06 +0200 Subject: [PATCH 050/122] fix os.read_dir with symlinks --- core/os/dir_bsd.odin | 73 ---------------------- core/os/dir_linux.odin | 72 --------------------- core/os/dir_openbsd.odin | 71 --------------------- core/os/{dir_darwin.odin => dir_unix.odin} | 28 +++++---- tests/core/normal.odin | 1 + tests/core/os/dir/alink.txt | 1 + tests/core/os/dir/b.txt | 0 tests/core/os/dir/sub/.gitkeep | 0 tests/core/os/os.odin | 35 +++++++++++ 9 files changed, 52 insertions(+), 229 deletions(-) delete mode 100644 core/os/dir_bsd.odin delete mode 100644 core/os/dir_linux.odin delete mode 100644 core/os/dir_openbsd.odin rename core/os/{dir_darwin.odin => dir_unix.odin} (64%) create mode 120000 tests/core/os/dir/alink.txt create mode 100644 tests/core/os/dir/b.txt create mode 100644 tests/core/os/dir/sub/.gitkeep create mode 100644 tests/core/os/os.odin diff --git a/core/os/dir_bsd.odin b/core/os/dir_bsd.odin deleted file mode 100644 index c0dc8ad1f..000000000 --- a/core/os/dir_bsd.odin +++ /dev/null @@ -1,73 +0,0 @@ -//+build freebsd, netbsd -package os - -import "core:mem" - -read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { - dirp: Dir - dirp, err = _fdopendir(fd) - if err != ERROR_NONE { - return - } - - defer _closedir(dirp) - - dirpath: string - dirpath, err = absolute_path_from_handle(fd) - - if err != ERROR_NONE { - return - } - - defer delete(dirpath) - - n := n - size := n - if n <= 0 { - n = -1 - size = 100 - } - - dfi := make([dynamic]File_Info, 0, size, allocator) - - for { - entry: Dirent - end_of_stream: bool - entry, err, end_of_stream = _readdir(dirp) - if err != ERROR_NONE { - for fi_ in dfi { - file_info_delete(fi_, allocator) - } - delete(dfi) - return - } else if end_of_stream { - break - } - - fi_: File_Info - filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) - - if filename == "." || filename == ".." { - continue - } - - fullpath := make([]byte, len(dirpath)+1+len(filename), context.temp_allocator) - copy(fullpath, dirpath) - copy(fullpath[len(dirpath):], "/") - copy(fullpath[len(dirpath)+1:], filename) - defer delete(fullpath, context.temp_allocator) - - fi_, err = stat(string(fullpath), allocator) - if err != ERROR_NONE { - for fi__ in dfi { - file_info_delete(fi__, allocator) - } - delete(dfi) - return - } - - append(&dfi, fi_) - } - - return dfi[:], ERROR_NONE -} diff --git a/core/os/dir_linux.odin b/core/os/dir_linux.odin deleted file mode 100644 index 3a51d7c70..000000000 --- a/core/os/dir_linux.odin +++ /dev/null @@ -1,72 +0,0 @@ -package os - -import "core:strings" -import "core:mem" -import "base:runtime" - -read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { - dirp: Dir - dirp, err = _fdopendir(fd) - if err != ERROR_NONE { - return - } - - defer _closedir(dirp) - - dirpath: string - dirpath, err = absolute_path_from_handle(fd) - - if err != ERROR_NONE { - return - } - - defer delete(dirpath) - - n := n - size := n - if n <= 0 { - n = -1 - size = 100 - } - - dfi := make([dynamic]File_Info, 0, size, allocator) - - for { - entry: Dirent - end_of_stream: bool - entry, err, end_of_stream = _readdir(dirp) - if err != ERROR_NONE { - for fi_ in dfi { - file_info_delete(fi_, allocator) - } - delete(dfi) - return - } else if end_of_stream { - break - } - - fi_: File_Info - filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) - - if filename == "." || filename == ".." { - continue - } - - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) - defer delete(fullpath, context.temp_allocator) - - fi_, err = stat(fullpath, allocator) - if err != ERROR_NONE { - for fi__ in dfi { - file_info_delete(fi__, allocator) - } - delete(dfi) - return - } - - append(&dfi, fi_) - } - - return dfi[:], ERROR_NONE -} diff --git a/core/os/dir_openbsd.odin b/core/os/dir_openbsd.odin deleted file mode 100644 index 465fd35ae..000000000 --- a/core/os/dir_openbsd.odin +++ /dev/null @@ -1,71 +0,0 @@ -package os - -import "core:strings" -import "core:mem" - -read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { - dirp: Dir - dirp, err = _fdopendir(fd) - if err != ERROR_NONE { - return - } - - defer _closedir(dirp) - - // XXX OpenBSD - dirpath: string - dirpath, err = absolute_path_from_handle(fd) - - if err != ERROR_NONE { - return - } - - defer delete(dirpath) - - n := n - size := n - if n <= 0 { - n = -1 - size = 100 - } - - dfi := make([dynamic]File_Info, 0, size, allocator) - - for { - entry: Dirent - end_of_stream: bool - entry, err, end_of_stream = _readdir(dirp) - if err != ERROR_NONE { - for fi_ in dfi { - file_info_delete(fi_, allocator) - } - delete(dfi) - return - } else if end_of_stream { - break - } - - fi_: File_Info - filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) - - if filename == "." || filename == ".." { - continue - } - - fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) - defer delete(fullpath, context.temp_allocator) - - fi_, err = stat(fullpath, allocator) - if err != ERROR_NONE { - for fi__ in dfi { - file_info_delete(fi__, allocator) - } - delete(dfi) - return - } - - append(&dfi, fi_) - } - - return dfi[:], ERROR_NONE -} diff --git a/core/os/dir_darwin.odin b/core/os/dir_unix.odin similarity index 64% rename from core/os/dir_darwin.odin rename to core/os/dir_unix.odin index 7d0f2936d..58cd873ae 100644 --- a/core/os/dir_darwin.odin +++ b/core/os/dir_unix.odin @@ -1,7 +1,7 @@ +//+build darwin, linux, netbsd, freebsd, openbsd package os import "core:strings" -import "core:mem" read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { dirp: Dir @@ -28,39 +28,41 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F } dfi := make([dynamic]File_Info, 0, size, allocator) + defer if err != ERROR_NONE { + for fi_ in dfi { + file_info_delete(fi_, allocator) + } + delete(dfi) + } for { entry: Dirent end_of_stream: bool entry, err, end_of_stream = _readdir(dirp) if err != ERROR_NONE { - for fi_ in dfi { - file_info_delete(fi_, allocator) - } - delete(dfi) return } else if end_of_stream { break } fi_: File_Info - filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) + filename := string(cstring(&entry.name[0])) if filename == "." || filename == ".." { continue } - fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) - defer delete(fullpath, context.temp_allocator) + fullpath := strings.join({ dirpath, filename }, "/", allocator) - fi_, err = stat(fullpath, allocator) + s: OS_Stat + s, err = _lstat(fullpath) if err != ERROR_NONE { - for fi__ in dfi { - file_info_delete(fi__, allocator) - } - delete(dfi) + delete(fullpath, allocator) return } + _fill_file_info_from_stat(&fi_, s) + fi_.fullpath = fullpath + fi_.name = path_base(fi_.fullpath) append(&dfi, fi_) } diff --git a/tests/core/normal.odin b/tests/core/normal.odin index 7d5795273..8cd3b3917 100644 --- a/tests/core/normal.odin +++ b/tests/core/normal.odin @@ -30,6 +30,7 @@ download_assets :: proc() { @(require) import "mem" @(require) import "net" @(require) import "odin" +@(require) import "os" @(require) import "path/filepath" @(require) import "reflect" @(require) import "runtime" diff --git a/tests/core/os/dir/alink.txt b/tests/core/os/dir/alink.txt new file mode 120000 index 000000000..1891a26c0 --- /dev/null +++ b/tests/core/os/dir/alink.txt @@ -0,0 +1 @@ +./a.txt \ No newline at end of file diff --git a/tests/core/os/dir/b.txt b/tests/core/os/dir/b.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/os/dir/sub/.gitkeep b/tests/core/os/dir/sub/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/os/os.odin b/tests/core/os/os.odin new file mode 100644 index 000000000..fd4fd28a8 --- /dev/null +++ b/tests/core/os/os.odin @@ -0,0 +1,35 @@ +package tests_core_os + +import "core:os" +import "core:slice" + +import "core:testing" + +@(test) +read_dir :: proc(t: ^testing.T) { + fd, errno := os.open(#directory + "/dir") + testing.expect_value(t, errno, os.ERROR_NONE) + defer os.close(fd) + + dir, errno2 := os.read_dir(fd, -1) + testing.expect_value(t, errno2, os.ERROR_NONE) + defer os.file_info_slice_delete(dir) + + slice.sort_by_key(dir, proc(fi: os.File_Info) -> string { return fi.name }) + + testing.expect_value(t, len(dir), 3) + + testing.expect_value(t, dir[0].name, "alink.txt") + testing.expect(t, !dir[0].is_dir, "is a directory") + when ODIN_OS == .Windows { + testing.expect(t, dir[0].mode & os.File_Mode_Sym_Link != 0, "not a symlink") + } else { + testing.expect(t, os.S_ISLNK(auto_cast dir[0].mode), "not a symlink") + } + + testing.expect_value(t, dir[1].name, "b.txt") + + testing.expect_value(t, dir[2].name, "sub") + testing.expect(t, dir[2].is_dir, "is not a directory") +} + From 90e573c54a76d3b1292cbe99102731abd6937305 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 3 Aug 2024 12:58:43 +0200 Subject: [PATCH 051/122] Add image.premultiply_alpha helper. --- core/image/common.odin | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/core/image/common.odin b/core/image/common.odin index 94321f644..6ae9850da 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -1320,6 +1320,42 @@ blend_pixel :: #force_inline proc(fg: [$N]$T, alpha: T, bg: [N]T) -> (res: [N]T) } blend :: proc{blend_single_channel, blend_pixel} +// For all pixels of the image, multiplies R, G and B by Alpha. This is useful mainly for games rendering anti-aliased transparent sprites. +// Grayscale with alpha images are supported as well. +// Note that some image formats like QOI explicitly do NOT support premultiplied alpha, so you will end up with a non-standard file. +premultiply_alpha :: proc(img: ^Image) -> (ok: bool) { + switch { + case img.channels == 2 && img.depth == 8: + pixels := mem.slice_data_cast([]GA_Pixel, img.pixels.buf[:]) + for &pixel in pixels { + pixel.r = u8(u32(pixel.r) * u32(pixel.g) / 0xFF) + } + return true + case img.channels == 2 && img.depth == 16: + pixels := mem.slice_data_cast([]GA_Pixel_16, img.pixels.buf[:]) + for &pixel in pixels { + pixel.r = u16(u32(pixel.r) * u32(pixel.g) / 0xFFFF) + } + return true + case img.channels == 4 && img.depth == 8: + pixels := mem.slice_data_cast([]RGBA_Pixel, img.pixels.buf[:]) + for &pixel in pixels { + pixel.r = u8(u32(pixel.r) * u32(pixel.a) / 0xFF) + pixel.g = u8(u32(pixel.g) * u32(pixel.a) / 0xFF) + pixel.b = u8(u32(pixel.b) * u32(pixel.a) / 0xFF) + } + return true + case img.channels == 4 && img.depth == 16: + pixels := mem.slice_data_cast([]RGBA_Pixel_16, img.pixels.buf[:]) + for &pixel in pixels { + pixel.r = u16(u32(pixel.r) * u32(pixel.a) / 0xFFFF) + pixel.g = u16(u32(pixel.g) * u32(pixel.a) / 0xFFFF) + pixel.b = u16(u32(pixel.b) * u32(pixel.a) / 0xFFFF) + } + return true + case: return false + } +} // Replicates grayscale values into RGB(A) 8- or 16-bit images as appropriate. // Returns early with `false` if already an RGB(A) image. From 61008232e4491ae2bb0008c913864dcadd80084f Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 3 Aug 2024 15:43:03 +0200 Subject: [PATCH 052/122] actually fail CI when NetBSD tests fail --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bdb94662f..0c9266328 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,7 @@ jobs: pkgin -y in gmake git bash python311 llvm clang ln -s /usr/pkg/bin/python3.11 /usr/bin/python3 run: | + set -e -x git config --global --add safe.directory $(pwd) gmake release ./odin version From 4dd846fa29a22cf3c758f1795c42c8b4b53db6db Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 3 Aug 2024 15:54:29 +0200 Subject: [PATCH 053/122] fix readir_r link name for netbsd --- core/os/os_netbsd.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index 2bda8abf7..da34a4168 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -306,7 +306,7 @@ foreign libc { @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir --- @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) --- - @(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- + @(link_name="__readdir_r30") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr --- @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr --- From e77977c8ef1b1dd7e788743bae6962ba74d8afe1 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 3 Aug 2024 23:56:19 +0200 Subject: [PATCH 054/122] fix vet errors in stb truetype --- vendor/stb/truetype/stb_truetype_wasm.odin | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vendor/stb/truetype/stb_truetype_wasm.odin b/vendor/stb/truetype/stb_truetype_wasm.odin index cb516bc1d..ff1d4fac5 100644 --- a/vendor/stb/truetype/stb_truetype_wasm.odin +++ b/vendor/stb/truetype/stb_truetype_wasm.odin @@ -7,7 +7,6 @@ import "base:runtime" import "core:c" import "core:math" -import "core:mem" import "core:slice" import "core:sort" @@ -69,7 +68,7 @@ pow :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) } @(require, linkage="strong", link_name="stbtt_fmod") fmod :: proc "c" (x, y: f64) -> f64 { - context = runtime.default_context(); + context = runtime.default_context() // NOTE: only called in the `stbtt_GetGlyphSDF` code path. panic("`math.round` is broken on 32 bit targets, see #3856") } From 71932628cc3c1957a98e998740b059df9b7dd392 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 10:08:48 +0100 Subject: [PATCH 055/122] Add alias --- core/os/os2/dir.odin | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/os/os2/dir.odin b/core/os/os2/dir.odin index 6334ee7b8..a41ef68f9 100644 --- a/core/os/os2/dir.odin +++ b/core/os/os2/dir.odin @@ -3,6 +3,8 @@ package os2 import "base:runtime" import "core:slice" +read_dir :: read_directory + @(require_results) read_directory :: proc(f: ^File, n: int, allocator: runtime.Allocator) -> (files: []File_Info, err: Error) { if f == nil { @@ -57,6 +59,7 @@ read_all_directory_by_path :: proc(path: string, allocator: runtime.Allocator) - } + Read_Directory_Iterator :: struct { f: ^File, impl: Read_Directory_Iterator_Impl, @@ -72,7 +75,6 @@ read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) { _read_directory_iterator_destroy(it) } - // NOTE(bill): `File_Info` does not need to deleted on each iteration. Any copies must be manually copied with `file_info_clone` @(require_results) read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) { From e60951a902976acfef74b863463bb116858366c5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 10:51:08 +0100 Subject: [PATCH 056/122] Begin converting `os.Errno` to be a `nil`-able type as a transition period --- core/crypto/rand_windows.odin | 2 +- core/os/os.odin | 6 + core/os/os2/errors.odin | 8 +- core/os/os2/errors_linux.odin | 2 +- core/os/os2/errors_windows.odin | 2 +- core/os/os2/file_stream.odin | 2 +- core/os/os2/process.odin | 2 +- core/os/os2/process_windows.odin | 14 +- core/os/os_darwin.odin | 357 ++++++++++++++++++++----------- core/os/os_essence.odin | 36 ++-- core/os/os_freebsd.odin | 291 ++++++++++++++++--------- core/os/os_haiku.odin | 14 +- core/os/os_js.odin | 92 +++++--- core/os/os_linux.odin | 256 +++++++++++----------- core/os/os_netbsd.odin | 347 +++++++++++++++++++++--------- core/os/os_openbsd.odin | 297 ++++++++++++++++--------- core/os/os_wasi.odin | 6 +- core/os/os_windows.odin | 59 +++-- core/prof/spall/spall_unix.odin | 4 +- core/sync/futex_haiku.odin | 11 +- core/sys/haiku/os.odin | 2 +- src/check_expr.cpp | 21 ++ 22 files changed, 1165 insertions(+), 666 deletions(-) diff --git a/core/crypto/rand_windows.odin b/core/crypto/rand_windows.odin index 9cd647cc1..6392cd51f 100644 --- a/core/crypto/rand_windows.odin +++ b/core/crypto/rand_windows.odin @@ -10,7 +10,7 @@ HAS_RAND_BYTES :: true _rand_bytes :: proc(dst: []byte) { ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)) if ret != os.ERROR_NONE { - switch ret { + #partial switch ret { case os.ERROR_INVALID_HANDLE: // The handle to the first parameter is invalid. // This should not happen here, since we explicitly pass nil to it diff --git a/core/os/os.odin b/core/os/os.odin index 51652a52b..3f48c59df 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -13,6 +13,12 @@ SEEK_SET :: 0 SEEK_CUR :: 1 SEEK_END :: 2 +Platform_Error :: _Platform_Error +Error :: Platform_Error +Errno :: Error // alias + +ERROR_NONE :: Errno(0) + write_string :: proc(fd: Handle, str: string) -> (int, Errno) { return write(fd, transmute([]byte)str) } diff --git a/core/os/os2/errors.odin b/core/os/os2/errors.odin index 2b9b3528e..e5a0bb722 100644 --- a/core/os/os2/errors.odin +++ b/core/os/os2/errors.odin @@ -3,7 +3,7 @@ package os2 import "core:io" import "base:runtime" -General_Error :: enum u32 { +General_Platform_Error :: enum u32 { None, Permission_Denied, @@ -29,7 +29,7 @@ General_Error :: enum u32 { Unsupported, } -Platform_Error :: enum i32 {None=0} +Platform_Platform_Error :: enum i32 {None=0} Error :: union #shared_nil { General_Error, @@ -43,7 +43,7 @@ ERROR_NONE :: Error{} -is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { +is_platform_Platform_Error :: proc(ferr: Error) -> (err: i32, ok: bool) { v := ferr.(Platform_Error) or_else {} return i32(v), i32(v) != 0 } @@ -104,7 +104,7 @@ error_string :: proc(ferr: Error) -> string { return "unknown error" } -print_error :: proc(f: ^File, ferr: Error, msg: string) { +print_Platform_Error :: proc(f: ^File, ferr: Error, msg: string) { TEMP_ALLOCATOR_GUARD() err_str := error_string(ferr) diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin index d7234ce8b..0da9e1452 100644 --- a/core/os/os2/errors_linux.odin +++ b/core/os/os2/errors_linux.odin @@ -142,7 +142,7 @@ _errno_strings : [linux.Errno]string = { } -_get_platform_error :: proc(errno: linux.Errno) -> Error { +_get_platform_Platform_Error :: proc(errno: linux.Errno) -> Error { #partial switch errno { case .NONE: return nil diff --git a/core/os/os2/errors_windows.odin b/core/os/os2/errors_windows.odin index 6421d26ee..00dacd491 100644 --- a/core/os/os2/errors_windows.odin +++ b/core/os/os2/errors_windows.odin @@ -20,7 +20,7 @@ _error_string :: proc(errno: i32) -> string { return "" } -_get_platform_error :: proc() -> Error { +_get_platform_Platform_Error :: proc() -> Error { err := win32.GetLastError() if err == 0 { return nil diff --git a/core/os/os2/file_stream.odin b/core/os/os2/file_stream.odin index 84176928d..89bd59809 100644 --- a/core/os/os2/file_stream.odin +++ b/core/os/os2/file_stream.odin @@ -15,7 +15,7 @@ to_reader :: to_stream @(private) -error_to_io_error :: proc(ferr: Error) -> io.Error { +error_to_io_Platform_Error :: proc(ferr: Error) -> io.Error { if ferr == nil { return .None } diff --git a/core/os/os2/process.odin b/core/os/os2/process.odin index 3f3e64668..f1309e468 100644 --- a/core/os/os2/process.odin +++ b/core/os/os2/process.odin @@ -370,7 +370,7 @@ Process_State :: struct { timeout (if specified) has reached zero. If the timeout is `TIMEOUT_INFINITE`, no timeout restriction is imposed and the procedure can block indefinately. - If the timeout has expired, the `General_Error.Timeout` is returned as + If the timeout has expired, the `GeneralPlatform_Error.Timeout` is returned as the error. If an error is returned for any other reason, other than timeout, the diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin index 47fd62401..57f162eab 100644 --- a/core/os/os2/process_windows.odin +++ b/core/os/os2/process_windows.odin @@ -101,7 +101,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator if selection >= {.PPid, .Priority} { entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = General_Error.Not_Exist + err = GeneralPlatform_Error.Not_Exist return } if .PPid in selection { @@ -147,7 +147,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator } if process_info.PebBaseAddress == nil { // Not sure what the error is - err = General_Error.Unsupported + err = GeneralPlatform_Error.Unsupported return } process_peb: win32.PEB @@ -210,7 +210,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields if selection >= {.PPid, .Priority} { // snap process entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = General_Error.Not_Exist + err = GeneralPlatform_Error.Not_Exist return } if .PPid in selection { @@ -239,7 +239,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields } if process_info.PebBaseAddress == nil { // Not sure what the error is - err = General_Error.Unsupported + err = GeneralPlatform_Error.Unsupported return } @@ -301,7 +301,7 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime if selection >= {.PPid, .Priority} { // snap process entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = General_Error.Not_Exist + err = GeneralPlatform_Error.Not_Exist return } if .PPid in selection { @@ -459,7 +459,7 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (process_stat } return case win32.WAIT_TIMEOUT: - err = General_Error.Timeout + err = GeneralPlatform_Error.Timeout return case: err = _get_platform_error() @@ -508,7 +508,7 @@ _process_entry_by_pid :: proc(pid: int) -> (entry: win32.PROCESSENTRY32W, err: E } status = win32.Process32NextW(snap, &entry) } - err = General_Error.Not_Exist + err = GeneralPlatform_Error.Not_Exist return } diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index e3748cce4..f72529682 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -10,146 +10,257 @@ import "core:c" Handle :: distinct i32 File_Time :: distinct u64 -Errno :: distinct int INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno : 0 -EPERM: Errno : 1 /* Operation not permitted */ -ENOENT: Errno : 2 /* No such file or directory */ -ESRCH: Errno : 3 /* No such process */ -EINTR: Errno : 4 /* Interrupted system call */ -EIO: Errno : 5 /* Input/output error */ -ENXIO: Errno : 6 /* Device not configured */ -E2BIG: Errno : 7 /* Argument list too long */ -ENOEXEC: Errno : 8 /* Exec format error */ -EBADF: Errno : 9 /* Bad file descriptor */ -ECHILD: Errno : 10 /* No child processes */ -EDEADLK: Errno : 11 /* Resource deadlock avoided */ -ENOMEM: Errno : 12 /* Cannot allocate memory */ -EACCES: Errno : 13 /* Permission denied */ -EFAULT: Errno : 14 /* Bad address */ -ENOTBLK: Errno : 15 /* Block device required */ -EBUSY: Errno : 16 /* Device / Resource busy */ -EEXIST: Errno : 17 /* File exists */ -EXDEV: Errno : 18 /* Cross-device link */ -ENODEV: Errno : 19 /* Operation not supported by device */ -ENOTDIR: Errno : 20 /* Not a directory */ -EISDIR: Errno : 21 /* Is a directory */ -EINVAL: Errno : 22 /* Invalid argument */ -ENFILE: Errno : 23 /* Too many open files in system */ -EMFILE: Errno : 24 /* Too many open files */ -ENOTTY: Errno : 25 /* Inappropriate ioctl for device */ -ETXTBSY: Errno : 26 /* Text file busy */ -EFBIG: Errno : 27 /* File too large */ -ENOSPC: Errno : 28 /* No space left on device */ -ESPIPE: Errno : 29 /* Illegal seek */ -EROFS: Errno : 30 /* Read-only file system */ -EMLINK: Errno : 31 /* Too many links */ -EPIPE: Errno : 32 /* Broken pipe */ +_Platform_Error :: enum i32 { + NONE = 0, + EPERM = 1, /* Operation not permitted */ + ENOENT = 2, /* No such file or directory */ + ESRCH = 3, /* No such process */ + EINTR = 4, /* Interrupted system call */ + EIO = 5, /* Input/output error */ + ENXIO = 6, /* Device not configured */ + E2BIG = 7, /* Argument list too long */ + ENOEXEC = 8, /* Exec format error */ + EBADF = 9, /* Bad file descriptor */ + ECHILD = 10, /* No child processes */ + EDEADLK = 11, /* Resource deadlock avoided */ + ENOMEM = 12, /* Cannot allocate memory */ + EACCES = 13, /* Permission denied */ + EFAULT = 14, /* Bad address */ + ENOTBLK = 15, /* Block device required */ + EBUSY = 16, /* Device / Resource busy */ + EEXIST = 17, /* File exists */ + EXDEV = 18, /* Cross-device link */ + ENODEV = 19, /* Operation not supported by device */ + ENOTDIR = 20, /* Not a directory */ + EISDIR = 21, /* Is a directory */ + EINVAL = 22, /* Invalid argument */ + ENFILE = 23, /* Too many open files in system */ + EMFILE = 24, /* Too many open files */ + ENOTTY = 25, /* Inappropriate ioctl for device */ + ETXTBSY = 26, /* Text file busy */ + EFBIG = 27, /* File too large */ + ENOSPC = 28, /* No space left on device */ + ESPIPE = 29, /* Illegal seek */ + EROFS = 30, /* Read-only file system */ + EMLINK = 31, /* Too many links */ + EPIPE = 32, /* Broken pipe */ -/* math software */ -EDOM: Errno : 33 /* Numerical argument out of domain */ -ERANGE: Errno : 34 /* Result too large */ + /* math software */ + EDOM = 33, /* Numerical argument out of domain */ + ERANGE = 34, /* Result too large */ -/* non-blocking and interrupt i/o */ -EAGAIN: Errno : 35 /* Resource temporarily unavailable */ -EWOULDBLOCK: Errno : EAGAIN /* Operation would block */ -EINPROGRESS: Errno : 36 /* Operation now in progress */ -EALREADY: Errno : 37 /* Operation already in progress */ + /* non-blocking and interrupt i/o */ + EAGAIN = 35, /* Resource temporarily unavailable */ + EWOULDBLOCK = EAGAIN, /* Operation would block */ + EINPROGRESS = 36, /* Operation now in progress */ + EALREADY = 37, /* Operation already in progress */ -/* ipc/network software -- argument errors */ -ENOTSOCK: Errno : 38 /* Socket operation on non-socket */ -EDESTADDRREQ: Errno : 39 /* Destination address required */ -EMSGSIZE: Errno : 40 /* Message too long */ -EPROTOTYPE: Errno : 41 /* Protocol wrong type for socket */ -ENOPROTOOPT: Errno : 42 /* Protocol not available */ -EPROTONOSUPPORT: Errno : 43 /* Protocol not supported */ -ESOCKTNOSUPPORT: Errno : 44 /* Socket type not supported */ -ENOTSUP: Errno : 45 /* Operation not supported */ -EOPNOTSUPP:: ENOTSUP -EPFNOSUPPORT: Errno : 46 /* Protocol family not supported */ -EAFNOSUPPORT: Errno : 47 /* Address family not supported by protocol family */ -EADDRINUSE: Errno : 48 /* Address already in use */ -EADDRNOTAVAIL: Errno : 49 /* Can't assign requested address */ + /* ipc/network software -- argument errors */ + ENOTSOCK = 38, /* Socket operation on non-socket */ + EDESTADDRREQ = 39, /* Destination address required */ + EMSGSIZE = 40, /* Message too long */ + EPROTOTYPE = 41, /* Protocol wrong type for socket */ + ENOPROTOOPT = 42, /* Protocol not available */ + EPROTONOSUPPOR = 43, /* Protocol not supported */ + ESOCKTNOSUPPOR = 44, /* Socket type not supported */ + ENOTSUP = 45, /* Operation not supported */ + EOPNOTSUPP = ENOTSUP, + EPFNOSUPPORT = 46, /* Protocol family not supported */ + EAFNOSUPPORT = 47, /* Address family not supported by protocol family */ + EADDRINUSE = 48, /* Address already in use */ + EADDRNOTAVAIL = 49, /* Can't assign requested address */ -/* ipc/network software -- operational errors */ -ENETDOWN: Errno : 50 /* Network is down */ -ENETUNREACH: Errno : 51 /* Network is unreachable */ -ENETRESET: Errno : 52 /* Network dropped connection on reset */ -ECONNABORTED: Errno : 53 /* Software caused connection abort */ -ECONNRESET: Errno : 54 /* Connection reset by peer */ -ENOBUFS: Errno : 55 /* No buffer space available */ -EISCONN: Errno : 56 /* Socket is already connected */ -ENOTCONN: Errno : 57 /* Socket is not connected */ -ESHUTDOWN: Errno : 58 /* Can't send after socket shutdown */ -ETOOMANYREFS: Errno : 59 /* Too many references: can't splice */ -ETIMEDOUT: Errno : 60 /* Operation timed out */ -ECONNREFUSED: Errno : 61 /* Connection refused */ + /* ipc/network software -- operational errors */ + ENETDOWN = 50, /* Network is down */ + ENETUNREAC = 51, /* Network is unreachable */ + ENETRESET = 52, /* Network dropped connection on reset */ + ECONNABORTE = 53, /* Software caused connection abort */ + ECONNRESET = 54, /* Connection reset by peer */ + ENOBUFS = 55, /* No buffer space available */ + EISCONN = 56, /* Socket is already connected */ + ENOTCONN = 57, /* Socket is not connected */ + ESHUTDOWN = 58, /* Can't send after socket shutdown */ + ETOOMANYREF = 59, /* Too many references: can't splice */ + ETIMEDOUT = 60, /* Operation timed out */ + ECONNREFUSE = 61, /* Connection refused */ -ELOOP: Errno : 62 /* Too many levels of symbolic links */ -ENAMETOOLONG: Errno : 63 /* File name too long */ + ELOOP = 62, /* Too many levels of symbolic links */ + ENAMETOOLON = 63, /* File name too long */ -/* should be rearranged */ -EHOSTDOWN: Errno : 64 /* Host is down */ -EHOSTUNREACH: Errno : 65 /* No route to host */ -ENOTEMPTY: Errno : 66 /* Directory not empty */ + /* should be rearranged */ + EHOSTDOWN = 64, /* Host is down */ + EHOSTUNREAC = 65, /* No route to host */ + ENOTEMPTY = 66, /* Directory not empty */ -/* quotas & mush */ -EPROCLIM: Errno : 67 /* Too many processes */ -EUSERS: Errno : 68 /* Too many users */ -EDQUOT: Errno : 69 /* Disc quota exceeded */ + /* quotas & mush */ + EPROCLIM = 67, /* Too many processes */ + EUSERS = 68, /* Too many users */ + EDQUOT = 69, /* Disc quota exceeded */ -/* Network File System */ -ESTALE: Errno : 70 /* Stale NFS file handle */ -EREMOTE: Errno : 71 /* Too many levels of remote in path */ -EBADRPC: Errno : 72 /* RPC struct is bad */ -ERPCMISMATCH: Errno : 73 /* RPC version wrong */ -EPROGUNAVAIL: Errno : 74 /* RPC prog. not avail */ -EPROGMISMATCH: Errno : 75 /* Program version wrong */ -EPROCUNAVAIL: Errno : 76 /* Bad procedure for program */ + /* Network File System */ + ESTALE = 70, /* Stale NFS file handle */ + EREMOTE = 71, /* Too many levels of remote in path */ + EBADRPC = 72, /* RPC struct is bad */ + ERPCMISMATC = 73, /* RPC version wrong */ + EPROGUNAVAI = 74, /* RPC prog. not avail */ + EPROGMISMATC = 75, /* Program version wrong */ + EPROCUNAVAI = 76, /* Bad procedure for program */ -ENOLCK: Errno : 77 /* No locks available */ -ENOSYS: Errno : 78 /* Function not implemented */ + ENOLC = 77, /* No locks available */ + ENOSY = 78, /* Function not implemented */ -EFTYPE: Errno : 79 /* Inappropriate file type or format */ -EAUTH: Errno : 80 /* Authentication error */ -ENEEDAUTH: Errno : 81 /* Need authenticator */ + EFTYP = 79, /* Inappropriate file type or format */ + EAUT = 80, /* Authentication error */ + ENEEDAUT = 81, /* Need authenticator */ -/* Intelligent device errors */ -EPWROFF: Errno : 82 /* Device power is off */ -EDEVERR: Errno : 83 /* Device error, e.g. paper out */ -EOVERFLOW: Errno : 84 /* Value too large to be stored in data type */ + /* Intelligent device errors */ + EPWROF = 82, /* Device power is off */ + EDEVER = 83, /* Device error, e.g. paper out */ + EOVERFLO = 84, /* Value too large to be stored in data type */ -/* Program loading errors */ -EBADEXEC: Errno : 85 /* Bad executable */ -EBADARCH: Errno : 86 /* Bad CPU type in executable */ -ESHLIBVERS: Errno : 87 /* Shared library version mismatch */ -EBADMACHO: Errno : 88 /* Malformed Macho file */ + /* Program loading errors */ + EBADEXE = 85, /* Bad executable */ + EBADARC = 86, /* Bad CPU type in executable */ + ESHLIBVER = 87, /* Shared library version mismatch */ + EBADMACH = 88, /* Malformed Macho file */ -ECANCELED: Errno : 89 /* Operation canceled */ + ECANCELE = 89, /* Operation canceled */ -EIDRM: Errno : 90 /* Identifier removed */ -ENOMSG: Errno : 91 /* No message of desired type */ -EILSEQ: Errno : 92 /* Illegal byte sequence */ -ENOATTR: Errno : 93 /* Attribute not found */ + EIDRM = 90, /* Identifier removed */ + ENOMSG = 91, /* No message of desired type */ + EILSEQ = 92, /* Illegal byte sequence */ + ENOATT = 93, /* Attribute not found */ -EBADMSG: Errno : 94 /* Bad message */ -EMULTIHOP: Errno : 95 /* Reserved */ -ENODATA: Errno : 96 /* No message available on STREAM */ -ENOLINK: Errno : 97 /* Reserved */ -ENOSR: Errno : 98 /* No STREAM resources */ -ENOSTR: Errno : 99 /* Not a STREAM */ -EPROTO: Errno : 100 /* Protocol error */ -ETIME: Errno : 101 /* STREAM ioctl timeout */ + EBADMS = 94, /* Bad message */ + EMULTIHO = 95, /* Reserved */ + ENODAT = 96, /* No message available on STREAM */ + ENOLIN = 97, /* Reserved */ + ENOSR = 98, /* No STREAM resources */ + ENOSTR = 99, /* Not a STREAM */ + EPROTO = 100, /* Protocol error */ + ETIME = 101, /* STREAM ioctl timeout */ -ENOPOLICY: Errno : 103 /* No such policy registered */ + ENOPOLIC = 103, /* No such policy registered */ -ENOTRECOVERABLE: Errno : 104 /* State not recoverable */ -EOWNERDEAD: Errno : 105 /* Previous owner died */ + ENOTRECOVERABL = 104, /* State not recoverable */ + EOWNERDEAD = 105, /* Previous owner died */ -EQFULL: Errno : 106 /* Interface output queue is full */ -ELAST: Errno : 106 /* Must be equal largest errno */ + EQFUL = 106, /* Interface output queue is full */ + ELAS = 106, /* Must be equal largest errno */ +} + + +EPERM :: Platform_Error.EPERM +ENOENT :: Platform_Error.ENOENT +ESRCH :: Platform_Error.ESRCH +EINTR :: Platform_Error.EINTR +EIO :: Platform_Error.EIO +ENXIO :: Platform_Error.ENXIO +E2BIG :: Platform_Error.E2BIG +ENOEXEC :: Platform_Error.ENOEXEC +EBADF :: Platform_Error.EBADF +ECHILD :: Platform_Error.ECHILD +EDEADLK :: Platform_Error.EDEADLK +ENOMEM :: Platform_Error.ENOMEM +EACCES :: Platform_Error.EACCES +EFAULT :: Platform_Error.EFAULT +ENOTBLK :: Platform_Error.ENOTBLK +EBUSY :: Platform_Error.EBUSY +EEXIST :: Platform_Error.EEXIST +EXDEV :: Platform_Error.EXDEV +ENODEV :: Platform_Error.ENODEV +ENOTDIR :: Platform_Error.ENOTDIR +EISDIR :: Platform_Error.EISDIR +EINVAL :: Platform_Error.EINVAL +ENFILE :: Platform_Error.ENFILE +EMFILE :: Platform_Error.EMFILE +ENOTTY :: Platform_Error.ENOTTY +ETXTBSY :: Platform_Error.ETXTBSY +EFBIG :: Platform_Error.EFBIG +ENOSPC :: Platform_Error.ENOSPC +ESPIPE :: Platform_Error.ESPIPE +EROFS :: Platform_Error.EROFS +EMLINK :: Platform_Error.EMLINK +EPIPE :: Platform_Error.EPIPE +EDOM :: Platform_Error.EDOM +ERANGE :: Platform_Error.ERANGE +EAGAIN :: Platform_Error.EAGAIN +EWOULDBLOCK :: Platform_Error.EWOULDBLOCK +EINPROGRESS :: Platform_Error.EINPROGRESS +EALREADY :: Platform_Error.EALREADY +ENOTSOCK :: Platform_Error.ENOTSOCK +EDESTADDRREQ :: Platform_Error.EDESTADDRREQ +EMSGSIZE :: Platform_Error.EMSGSIZE +EPROTOTYPE :: Platform_Error.EPROTOTYPE +ENOPROTOOPT :: Platform_Error.ENOPROTOOPT +EPROTONOSUPPOR :: Platform_Error.EPROTONOSUPPOR +ESOCKTNOSUPPOR :: Platform_Error.ESOCKTNOSUPPOR +ENOTSUP :: Platform_Error.ENOTSUP +EOPNOTSUPP :: Platform_Error.EOPNOTSUPP +EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT +EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT +EADDRINUSE :: Platform_Error.EADDRINUSE +EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL +ENETDOWN :: Platform_Error.ENETDOWN +ENETUNREAC :: Platform_Error.ENETUNREAC +ENETRESET :: Platform_Error.ENETRESET +ECONNABORTE :: Platform_Error.ECONNABORTE +ECONNRESET :: Platform_Error.ECONNRESET +ENOBUFS :: Platform_Error.ENOBUFS +EISCONN :: Platform_Error.EISCONN +ENOTCONN :: Platform_Error.ENOTCONN +ESHUTDOWN :: Platform_Error.ESHUTDOWN +ETOOMANYREF :: Platform_Error.ETOOMANYREF +ETIMEDOUT :: Platform_Error.ETIMEDOUT +ECONNREFUSE :: Platform_Error.ECONNREFUSE +ELOOP :: Platform_Error.ELOOP +ENAMETOOLON :: Platform_Error.ENAMETOOLON +EHOSTDOWN :: Platform_Error.EHOSTDOWN +EHOSTUNREAC :: Platform_Error.EHOSTUNREAC +ENOTEMPTY :: Platform_Error.ENOTEMPTY +EPROCLIM :: Platform_Error.EPROCLIM +EUSERS :: Platform_Error.EUSERS +EDQUOT :: Platform_Error.EDQUOT +ESTALE :: Platform_Error.ESTALE +EREMOTE :: Platform_Error.EREMOTE +EBADRPC :: Platform_Error.EBADRPC +ERPCMISMATC :: Platform_Error.ERPCMISMATC +EPROGUNAVAI :: Platform_Error.EPROGUNAVAI +EPROGMISMATC :: Platform_Error.EPROGMISMATC +EPROCUNAVAI :: Platform_Error.EPROCUNAVAI +ENOLC :: Platform_Error.ENOLC +ENOSY :: Platform_Error.ENOSY +EFTYP :: Platform_Error.EFTYP +EAUT :: Platform_Error.EAUT +ENEEDAUT :: Platform_Error.ENEEDAUT +EPWROF :: Platform_Error.EPWROF +EDEVER :: Platform_Error.EDEVER +EOVERFLO :: Platform_Error.EOVERFLO +EBADEXE :: Platform_Error.EBADEXE +EBADARC :: Platform_Error.EBADARC +ESHLIBVER :: Platform_Error.ESHLIBVER +EBADMACH :: Platform_Error.EBADMACH +ECANCELE :: Platform_Error.ECANCELE +EIDRM :: Platform_Error.EIDRM +ENOMSG :: Platform_Error.ENOMSG +EILSEQ :: Platform_Error.EILSEQ +ENOATT :: Platform_Error.ENOATT +EBADMS :: Platform_Error.EBADMS +EMULTIHO :: Platform_Error.EMULTIHO +ENODAT :: Platform_Error.ENODAT +ENOLIN :: Platform_Error.ENOLIN +ENOSR :: Platform_Error.ENOSR +ENOSTR :: Platform_Error.ENOSTR +EPROTO :: Platform_Error.EPROTO +ETIME :: Platform_Error.ETIME +ENOPOLIC :: Platform_Error.ENOPOLIC +ENOTRECOVERABL :: Platform_Error.ENOTRECOVERABL +EOWNERDEAD :: Platform_Error.EOWNERDEAD +EQFUL :: Platform_Error.EQFUL +ELAS :: Platform_Error.ELAS O_RDONLY :: 0x0000 O_WRONLY :: 0x0001 @@ -524,12 +635,12 @@ foreign dl { @(link_name="dlerror") _unix_dlerror :: proc() -> cstring --- } -get_last_error :: proc "contextless" () -> int { - return int(__error()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__error()^) } get_last_error_string :: proc() -> string { - return cast(string)_darwin_string_error(cast(c.int)get_last_error()) + return string(_darwin_string_error(__error()^)) } @@ -548,7 +659,7 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, i32(flags), u16(mode)) if handle == -1 { - return INVALID_HANDLE, cast(Errno)get_last_error() + return INVALID_HANDLE, get_last_error() } /* diff --git a/core/os/os_essence.odin b/core/os/os_essence.odin index e4281f6c9..98abb432d 100644 --- a/core/os/os_essence.odin +++ b/core/os/os_essence.odin @@ -2,54 +2,54 @@ package os import "core:sys/es" -Handle :: distinct int; -Errno :: distinct int; +Handle :: distinct int +_Platform_Error :: enum i32 {NONE} -ERROR_NONE :: (Errno) (es.SUCCESS); +ERROR_NONE :: Errno(es.SUCCESS) -O_RDONLY :: 0x1; -O_WRONLY :: 0x2; -O_CREATE :: 0x4; -O_TRUNC :: 0x8; +O_RDONLY :: 0x1 +O_WRONLY :: 0x2 +O_CREATE :: 0x4 +O_TRUNC :: 0x8 -stderr : Handle = 0; +stderr : Handle = 0 current_thread_id :: proc "contextless" () -> int { - return (int) (es.ThreadGetID(es.CURRENT_THREAD)); + return (int) (es.ThreadGetID(es.CURRENT_THREAD)) } heap_alloc :: proc(size: int, zero_memory := true) -> rawptr { - return es.HeapAllocate(size, zero_memory); + return es.HeapAllocate(size, zero_memory) } heap_free :: proc(ptr: rawptr) { - es.HeapFree(ptr); + es.HeapFree(ptr) } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { - return es.HeapReallocate(ptr, new_size, false); + return es.HeapReallocate(ptr, new_size, false) } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { - return (Handle) (0), (Errno) (1); + return (Handle) (0), (Errno) (1) } close :: proc(fd: Handle) -> Errno { - return (Errno) (1); + return (Errno) (1) } file_size :: proc(fd: Handle) -> (i64, Errno) { - return (i64) (0), (Errno) (1); + return (i64) (0), (Errno) (1) } read :: proc(fd: Handle, data: []byte) -> (int, Errno) { - return (int) (0), (Errno) (1); + return (int) (0), (Errno) (1) } write :: proc(fd: Handle, data: []u8) -> (int, Errno) { - return (int) (0), (Errno) (1); + return (int) (0), (Errno) (1) } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { - return (i64) (0), (Errno) (1); + return (i64) (0), (Errno) (1) } diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 36ada0948..7090a7773 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -9,105 +9,200 @@ import "core:c" Handle :: distinct i32 File_Time :: distinct u64 -Errno :: distinct i32 INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno : 0 -EPERM: Errno : 1 -ENOENT: Errno : 2 -ESRCH: Errno : 3 -EINTR: Errno : 4 -EIO: Errno : 5 -ENXIO: Errno : 6 -E2BIG: Errno : 7 -ENOEXEC: Errno : 8 -EBADF: Errno : 9 -ECHILD: Errno : 10 -EBEADLK: Errno : 11 -ENOMEM: Errno : 12 -EACCESS: Errno : 13 -EFAULT: Errno : 14 -ENOTBLK: Errno : 15 -EBUSY: Errno : 16 -EEXIST: Errno : 17 -EXDEV: Errno : 18 -ENODEV: Errno : 19 -ENOTDIR: Errno : 20 -EISDIR: Errno : 21 -EINVAL: Errno : 22 -ENFILE: Errno : 23 -EMFILE: Errno : 24 -ENOTTY: Errno : 25 -ETXTBSY: Errno : 26 -EFBIG: Errno : 27 -ENOSPC: Errno : 28 -ESPIPE: Errno : 29 -EROFS: Errno : 30 -EMLINK: Errno : 31 -EPIPE: Errno : 32 -EDOM: Errno : 33 -ERANGE: Errno : 34 /* Result too large */ -EAGAIN: Errno : 35 -EINPROGRESS: Errno : 36 -EALREADY: Errno : 37 -ENOTSOCK: Errno : 38 -EDESTADDRREQ: Errno : 39 -EMSGSIZE: Errno : 40 -EPROTOTYPE: Errno : 41 -ENOPROTOOPT: Errno : 42 -EPROTONOSUPPORT: Errno : 43 -ESOCKTNOSUPPORT: Errno : 44 -EOPNOTSUPP: Errno : 45 -EPFNOSUPPORT: Errno : 46 -EAFNOSUPPORT: Errno : 47 -EADDRINUSE: Errno : 48 -EADDRNOTAVAIL: Errno : 49 -ENETDOWN: Errno : 50 -ENETUNREACH: Errno : 51 -ENETRESET: Errno : 52 -ECONNABORTED: Errno : 53 -ECONNRESET: Errno : 54 -ENOBUFS: Errno : 55 -EISCONN: Errno : 56 -ENOTCONN: Errno : 57 -ESHUTDOWN: Errno : 58 -ETIMEDOUT: Errno : 60 -ECONNREFUSED: Errno : 61 -ELOOP: Errno : 62 -ENAMETOOLING: Errno : 63 -EHOSTDOWN: Errno : 64 -EHOSTUNREACH: Errno : 65 -ENOTEMPTY: Errno : 66 -EPROCLIM: Errno : 67 -EUSERS: Errno : 68 -EDQUOT: Errno : 69 -ESTALE: Errno : 70 -EBADRPC: Errno : 72 -ERPCMISMATCH: Errno : 73 -EPROGUNAVAIL: Errno : 74 -EPROGMISMATCH: Errno : 75 -EPROCUNAVAIL: Errno : 76 -ENOLCK: Errno : 77 -ENOSYS: Errno : 78 -EFTYPE: Errno : 79 -EAUTH: Errno : 80 -ENEEDAUTH: Errno : 81 -EIDRM: Errno : 82 -ENOMSG: Errno : 83 -EOVERFLOW: Errno : 84 -ECANCELED: Errno : 85 -EILSEQ: Errno : 86 -ENOATTR: Errno : 87 -EDOOFUS: Errno : 88 -EBADMSG: Errno : 89 -EMULTIHOP: Errno : 90 -ENOLINK: Errno : 91 -EPROTO: Errno : 92 -ENOTCAPABLE: Errno : 93 -ECAPMODE: Errno : 94 -ENOTRECOVERABLE: Errno : 95 -EOWNERDEAD: Errno : 96 +_Platform_Error :: enum i32 { + NONE = 0, + EPERM = 1, + ENOENT = 2, + ESRCH = 3, + EINTR = 4, + EIO = 5, + ENXIO = 6, + E2BIG = 7, + ENOEXEC = 8, + EBADF = 9, + ECHILD = 10, + EBEADLK = 11, + ENOMEM = 12, + EACCESS = 13, + EFAULT = 14, + ENOTBLK = 15, + EBUSY = 16, + EEXIST = 17, + EXDEV = 18, + ENODEV = 19, + ENOTDIR = 20, + EISDIR = 21, + EINVAL = 22, + ENFILE = 23, + EMFILE = 24, + ENOTTY = 25, + ETXTBSY = 26, + EFBIG = 27, + ENOSPC = 28, + ESPIPE = 29, + EROFS = 30, + EMLINK = 31, + EPIPE = 32, + EDOM = 33, + ERANGE = 34, /* Result too large */ + EAGAIN = 35, + EINPROGRESS = 36, + EALREADY = 37, + ENOTSOCK = 38, + EDESTADDRREQ = 39, + EMSGSIZE = 40, + EPROTOTYPE = 41, + ENOPROTOOPT = 42, + EPROTONOSUPPORT = 43, + ESOCKTNOSUPPORT = 44, + EOPNOTSUPP = 45, + EPFNOSUPPORT = 46, + EAFNOSUPPORT = 47, + EADDRINUSE = 48, + EADDRNOTAVAIL = 49, + ENETDOWN = 50, + ENETUNREACH = 51, + ENETRESET = 52, + ECONNABORTED = 53, + ECONNRESET = 54, + ENOBUFS = 55, + EISCONN = 56, + ENOTCONN = 57, + ESHUTDOWN = 58, + ETIMEDOUT = 60, + ECONNREFUSED = 61, + ELOOP = 62, + ENAMETOOLING = 63, + EHOSTDOWN = 64, + EHOSTUNREACH = 65, + ENOTEMPTY = 66, + EPROCLIM = 67, + EUSERS = 68, + EDQUOT = 69, + ESTALE = 70, + EBADRPC = 72, + ERPCMISMATCH = 73, + EPROGUNAVAIL = 74, + EPROGMISMATCH = 75, + EPROCUNAVAIL = 76, + ENOLCK = 77, + ENOSYS = 78, + EFTYPE = 79, + EAUTH = 80, + ENEEDAUTH = 81, + EIDRM = 82, + ENOMSG = 83, + EOVERFLOW = 84, + ECANCELED = 85, + EILSEQ = 86, + ENOATTR = 87, + EDOOFUS = 88, + EBADMSG = 89, + EMULTIHOP = 90, + ENOLINK = 91, + EPROTO = 92, + ENOTCAPABLE = 93, + ECAPMODE = 94, + ENOTRECOVERABLE = 95, + EOWNERDEAD = 96, +} +EPERM :: Platform_Error.EPERM +ENOENT :: Platform_Error.ENOENT +ESRCH :: Platform_Error.ESRCH +EINTR :: Platform_Error.EINTR +EIO :: Platform_Error.EIO +ENXIO :: Platform_Error.ENXIO +E2BIG :: Platform_Error.E2BIG +ENOEXEC :: Platform_Error.ENOEXEC +EBADF :: Platform_Error.EBADF +ECHILD :: Platform_Error.ECHILD +EBEADLK :: Platform_Error.EBEADLK +ENOMEM :: Platform_Error.ENOMEM +EACCESS :: Platform_Error.EACCESS +EFAULT :: Platform_Error.EFAULT +ENOTBLK :: Platform_Error.ENOTBLK +EBUSY :: Platform_Error.EBUSY +EEXIST :: Platform_Error.EEXIST +EXDEV :: Platform_Error.EXDEV +ENODEV :: Platform_Error.ENODEV +ENOTDIR :: Platform_Error.ENOTDIR +EISDIR :: Platform_Error.EISDIR +EINVAL :: Platform_Error.EINVAL +ENFILE :: Platform_Error.ENFILE +EMFILE :: Platform_Error.EMFILE +ENOTTY :: Platform_Error.ENOTTY +ETXTBSY :: Platform_Error.ETXTBSY +EFBIG :: Platform_Error.EFBIG +ENOSPC :: Platform_Error.ENOSPC +ESPIPE :: Platform_Error.ESPIPE +EROFS :: Platform_Error.EROFS +EMLINK :: Platform_Error.EMLINK +EPIPE :: Platform_Error.EPIPE +EDOM :: Platform_Error.EDOM +ERANGE :: Platform_Error.ERANGE +EAGAIN :: Platform_Error.EAGAIN +EINPROGRESS :: Platform_Error.EINPROGRESS +EALREADY :: Platform_Error.EALREADY +ENOTSOCK :: Platform_Error.ENOTSOCK +EDESTADDRREQ :: Platform_Error.EDESTADDRREQ +EMSGSIZE :: Platform_Error.EMSGSIZE +EPROTOTYPE :: Platform_Error.EPROTOTYPE +ENOPROTOOPT :: Platform_Error.ENOPROTOOPT +EPROTONOSUPPORT :: Platform_Error.EPROTONOSUPPORT +ESOCKTNOSUPPORT :: Platform_Error.ESOCKTNOSUPPORT +EOPNOTSUPP :: Platform_Error.EOPNOTSUPP +EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT +EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT +EADDRINUSE :: Platform_Error.EADDRINUSE +EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL +ENETDOWN :: Platform_Error.ENETDOWN +ENETUNREACH :: Platform_Error.ENETUNREACH +ENETRESET :: Platform_Error.ENETRESET +ECONNABORTED :: Platform_Error.ECONNABORTED +ECONNRESET :: Platform_Error.ECONNRESET +ENOBUFS :: Platform_Error.ENOBUFS +EISCONN :: Platform_Error.EISCONN +ENOTCONN :: Platform_Error.ENOTCONN +ESHUTDOWN :: Platform_Error.ESHUTDOWN +ETIMEDOUT :: Platform_Error.ETIMEDOUT +ECONNREFUSED :: Platform_Error.ECONNREFUSED +ELOOP :: Platform_Error.ELOOP +ENAMETOOLING :: Platform_Error.ENAMETOOLING +EHOSTDOWN :: Platform_Error.EHOSTDOWN +EHOSTUNREACH :: Platform_Error.EHOSTUNREACH +ENOTEMPTY :: Platform_Error.ENOTEMPTY +EPROCLIM :: Platform_Error.EPROCLIM +EUSERS :: Platform_Error.EUSERS +EDQUOT :: Platform_Error.EDQUOT +ESTALE :: Platform_Error.ESTALE +EBADRPC :: Platform_Error.EBADRPC +ERPCMISMATCH :: Platform_Error.ERPCMISMATCH +EPROGUNAVAIL :: Platform_Error.EPROGUNAVAIL +EPROGMISMATCH :: Platform_Error.EPROGMISMATCH +EPROCUNAVAIL :: Platform_Error.EPROCUNAVAIL +ENOLCK :: Platform_Error.ENOLCK +ENOSYS :: Platform_Error.ENOSYS +EFTYPE :: Platform_Error.EFTYPE +EAUTH :: Platform_Error.EAUTH +ENEEDAUTH :: Platform_Error.ENEEDAUTH +EIDRM :: Platform_Error.EIDRM +ENOMSG :: Platform_Error.ENOMSG +EOVERFLOW :: Platform_Error.EOVERFLOW +ECANCELED :: Platform_Error.ECANCELED +EILSEQ :: Platform_Error.EILSEQ +ENOATTR :: Platform_Error.ENOATTR +EDOOFUS :: Platform_Error.EDOOFUS +EBADMSG :: Platform_Error.EBADMSG +EMULTIHOP :: Platform_Error.EMULTIHOP +ENOLINK :: Platform_Error.ENOLINK +EPROTO :: Platform_Error.EPROTO +ENOTCAPABLE :: Platform_Error.ENOTCAPABLE +ECAPMODE :: Platform_Error.ECAPMODE +ENOTRECOVERABLE :: Platform_Error.ENOTRECOVERABLE +EOWNERDEAD :: Platform_Error.EOWNERDEAD O_RDONLY :: 0x00000 O_WRONLY :: 0x00001 @@ -324,8 +419,8 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } -get_last_error :: proc "contextless" () -> int { - return int(__errno_location()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__errno_location()^) } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index 06052fc42..03e2c5e64 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -10,16 +10,14 @@ import "core:sys/haiku" Handle :: i32 Pid :: i32 File_Time :: i64 -Errno :: i32 +_Platform_Error :: haiku.Errno MAX_PATH :: haiku.PATH_MAX -ENOSYS :: int(haiku.Errno.POSIX_ERROR_BASE) + 9 +ENOSYS :: _Platform_Error(i32(haiku.Errno.POSIX_ERROR_BASE) + 9) INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno: 0 - stdin: Handle = 0 stdout: Handle = 1 stderr: Handle = 2 @@ -183,8 +181,8 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } -get_last_error :: proc "contextless" () -> int { - return int(__error()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__error()^) } fork :: proc() -> (Pid, Errno) { @@ -391,8 +389,8 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } defer _unix_free(path_ptr) - path_cstr := transmute(cstring)path_ptr - path = strings.clone( string(path_cstr) ) + path_cstr := cstring(path_ptr) + path = strings.clone(string(path_cstr)) return path, ERROR_NONE } diff --git a/core/os/os_js.odin b/core/os/os_js.odin index 8b61cb7ed..f27b13097 100644 --- a/core/os/os_js.odin +++ b/core/os/os_js.odin @@ -161,7 +161,40 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F Handle :: distinct uintptr File_Time :: distinct u64 -Errno :: distinct int + +_Platform_Error :: enum i32 { + NONE = 0, + FILE_NOT_FOUND = 2, + PATH_NOT_FOUND = 3, + ACCESS_DENIED = 5, + INVALID_HANDLE = 6, + NOT_ENOUGH_MEMORY = 8, + NO_MORE_FILES = 18, + HANDLE_EOF = 38, + NETNAME_DELETED = 64, + FILE_EXISTS = 80, + INVALID_PARAMETER = 87, + BROKEN_PIPE = 109, + BUFFER_OVERFLOW = 111, + INSUFFICIENT_BUFFER = 122, + MOD_NOT_FOUND = 126, + PROC_NOT_FOUND = 127, + DIR_NOT_EMPTY = 145, + ALREADY_EXISTS = 183, + ENVVAR_NOT_FOUND = 203, + MORE_DATA = 234, + OPERATION_ABORTED = 995, + IO_PENDING = 997, + NOT_FOUND = 1168, + PRIVILEGE_NOT_HELD = 1314, + WSAEACCES = 10013, + WSAECONNRESET = 10054, + + // Windows reserves errors >= 1<<29 for application use + FILE_IS_PIPE = 1<<29 + 0, + FILE_IS_NOT_DIR = 1<<29 + 1, + NEGATIVE_OFFSET = 1<<29 + 2, +} INVALID_HANDLE :: ~Handle(0) @@ -182,37 +215,36 @@ O_ASYNC :: 0x02000 O_CLOEXEC :: 0x80000 -ERROR_NONE: Errno : 0 -ERROR_FILE_NOT_FOUND: Errno : 2 -ERROR_PATH_NOT_FOUND: Errno : 3 -ERROR_ACCESS_DENIED: Errno : 5 -ERROR_INVALID_HANDLE: Errno : 6 -ERROR_NOT_ENOUGH_MEMORY: Errno : 8 -ERROR_NO_MORE_FILES: Errno : 18 -ERROR_HANDLE_EOF: Errno : 38 -ERROR_NETNAME_DELETED: Errno : 64 -ERROR_FILE_EXISTS: Errno : 80 -ERROR_INVALID_PARAMETER: Errno : 87 -ERROR_BROKEN_PIPE: Errno : 109 -ERROR_BUFFER_OVERFLOW: Errno : 111 -ERROR_INSUFFICIENT_BUFFER: Errno : 122 -ERROR_MOD_NOT_FOUND: Errno : 126 -ERROR_PROC_NOT_FOUND: Errno : 127 -ERROR_DIR_NOT_EMPTY: Errno : 145 -ERROR_ALREADY_EXISTS: Errno : 183 -ERROR_ENVVAR_NOT_FOUND: Errno : 203 -ERROR_MORE_DATA: Errno : 234 -ERROR_OPERATION_ABORTED: Errno : 995 -ERROR_IO_PENDING: Errno : 997 -ERROR_NOT_FOUND: Errno : 1168 -ERROR_PRIVILEGE_NOT_HELD: Errno : 1314 -WSAEACCES: Errno : 10013 -WSAECONNRESET: Errno : 10054 +ERROR_FILE_NOT_FOUND :: Platform_Error.FILE_NOT_FOUND +ERROR_PATH_NOT_FOUND :: Platform_Error.PATH_NOT_FOUND +ERROR_ACCESS_DENIED :: Platform_Error.ACCESS_DENIED +ERROR_INVALID_HANDLE :: Platform_Error.INVALID_HANDLE +ERROR_NOT_ENOUGH_MEMORY :: Platform_Error.NOT_ENOUGH_MEMORY +ERROR_NO_MORE_FILES :: Platform_Error.NO_MORE_FILES +ERROR_HANDLE_EOF :: Platform_Error.HANDLE_EOF +ERROR_NETNAME_DELETED :: Platform_Error.NETNAME_DELETED +ERROR_FILE_EXISTS :: Platform_Error.FILE_EXISTS +ERROR_INVALID_PARAMETER :: Platform_Error.INVALID_PARAMETER +ERROR_BROKEN_PIPE :: Platform_Error.BROKEN_PIPE +ERROR_BUFFER_OVERFLOW :: Platform_Error.BUFFER_OVERFLOW +ERROR_INSUFFICIENT_BUFFER :: Platform_Error.INSUFFICIENT_BUFFER +ERROR_MOD_NOT_FOUND :: Platform_Error.MOD_NOT_FOUND +ERROR_PROC_NOT_FOUND :: Platform_Error.PROC_NOT_FOUND +ERROR_DIR_NOT_EMPTY :: Platform_Error.DIR_NOT_EMPTY +ERROR_ALREADY_EXISTS :: Platform_Error.ALREADY_EXISTS +ERROR_ENVVAR_NOT_FOUND :: Platform_Error.ENVVAR_NOT_FOUND +ERROR_MORE_DATA :: Platform_Error.MORE_DATA +ERROR_OPERATION_ABORTED :: Platform_Error.OPERATION_ABORTED +ERROR_IO_PENDING :: Platform_Error.IO_PENDING +ERROR_NOT_FOUND :: Platform_Error.NOT_FOUND +ERROR_PRIVILEGE_NOT_HELD :: Platform_Error.PRIVILEGE_NOT_HELD +WSAEACCES :: Platform_Error.WSAEACCES +WSAECONNRESET :: Platform_Error.WSAECONNRESET // Windows reserves errors >= 1<<29 for application use -ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0 -ERROR_FILE_IS_NOT_DIR: Errno : 1<<29 + 1 -ERROR_NEGATIVE_OFFSET: Errno : 1<<29 + 2 +ERROR_FILE_IS_PIPE :: Platform_Error.FILE_IS_PIPE +ERROR_FILE_IS_NOT_DIR :: Platform_Error.FILE_IS_NOT_DIR +ERROR_NEGATIVE_OFFSET :: Platform_Error.NEGATIVE_OFFSET // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index ebc1b3600..ace24d26a 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -20,148 +20,148 @@ import "base:intrinsics" // all that about compatibility. But we don't want to push experimental changes // and have people's code break while it's still work in progress. import unix "core:sys/unix" +import linux "core:sys/linux" Handle :: distinct i32 Pid :: distinct i32 File_Time :: distinct u64 -Errno :: distinct i32 Socket :: distinct int INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno : 0 -EPERM: Errno : 1 -ENOENT: Errno : 2 -ESRCH: Errno : 3 -EINTR: Errno : 4 -EIO: Errno : 5 -ENXIO: Errno : 6 -EBADF: Errno : 9 -EAGAIN: Errno : 11 -ENOMEM: Errno : 12 -EACCES: Errno : 13 -EFAULT: Errno : 14 -EEXIST: Errno : 17 -ENODEV: Errno : 19 -ENOTDIR: Errno : 20 -EISDIR: Errno : 21 -EINVAL: Errno : 22 -ENFILE: Errno : 23 -EMFILE: Errno : 24 -ETXTBSY: Errno : 26 -EFBIG: Errno : 27 -ENOSPC: Errno : 28 -ESPIPE: Errno : 29 -EROFS: Errno : 30 -EPIPE: Errno : 32 +_Platform_Error :: linux.Errno +EPERM :: Platform_Error.EPERM +ENOENT :: Platform_Error.ENOENT +ESRCH :: Platform_Error.ESRCH +EINTR :: Platform_Error.EINTR +EIO :: Platform_Error.EIO +ENXIO :: Platform_Error.ENXIO +EBADF :: Platform_Error.EBADF +EAGAIN :: Platform_Error.EAGAIN +ENOMEM :: Platform_Error.ENOMEM +EACCES :: Platform_Error.EACCES +EFAULT :: Platform_Error.EFAULT +EEXIST :: Platform_Error.EEXIST +ENODEV :: Platform_Error.ENODEV +ENOTDIR :: Platform_Error.ENOTDIR +EISDIR :: Platform_Error.EISDIR +EINVAL :: Platform_Error.EINVAL +ENFILE :: Platform_Error.ENFILE +EMFILE :: Platform_Error.EMFILE +ETXTBSY :: Platform_Error.ETXTBSY +EFBIG :: Platform_Error.EFBIG +ENOSPC :: Platform_Error.ENOSPC +ESPIPE :: Platform_Error.ESPIPE +EROFS :: Platform_Error.EROFS +EPIPE :: Platform_Error.EPIPE -ERANGE: Errno : 34 /* Result too large */ -EDEADLK: Errno : 35 /* Resource deadlock would occur */ -ENAMETOOLONG: Errno : 36 /* File name too long */ -ENOLCK: Errno : 37 /* No record locks available */ +ERANGE :: Platform_Error.ERANGE /* Result too large */ +EDEADLK :: Platform_Error.EDEADLK /* Resource deadlock would occur */ +ENAMETOOLONG :: Platform_Error.ENAMETOOLONG /* File name too long */ +ENOLCK :: Platform_Error.ENOLCK /* No record locks available */ -ENOSYS: Errno : 38 /* Invalid system call number */ +ENOSYS :: Platform_Error.ENOSYS /* Invalid system call number */ -ENOTEMPTY: Errno : 39 /* Directory not empty */ -ELOOP: Errno : 40 /* Too many symbolic links encountered */ -EWOULDBLOCK: Errno : EAGAIN /* Operation would block */ -ENOMSG: Errno : 42 /* No message of desired type */ -EIDRM: Errno : 43 /* Identifier removed */ -ECHRNG: Errno : 44 /* Channel number out of range */ -EL2NSYNC: Errno : 45 /* Level 2 not synchronized */ -EL3HLT: Errno : 46 /* Level 3 halted */ -EL3RST: Errno : 47 /* Level 3 reset */ -ELNRNG: Errno : 48 /* Link number out of range */ -EUNATCH: Errno : 49 /* Protocol driver not attached */ -ENOCSI: Errno : 50 /* No CSI structure available */ -EL2HLT: Errno : 51 /* Level 2 halted */ -EBADE: Errno : 52 /* Invalid exchange */ -EBADR: Errno : 53 /* Invalid request descriptor */ -EXFULL: Errno : 54 /* Exchange full */ -ENOANO: Errno : 55 /* No anode */ -EBADRQC: Errno : 56 /* Invalid request code */ -EBADSLT: Errno : 57 /* Invalid slot */ -EDEADLOCK: Errno : EDEADLK -EBFONT: Errno : 59 /* Bad font file format */ -ENOSTR: Errno : 60 /* Device not a stream */ -ENODATA: Errno : 61 /* No data available */ -ETIME: Errno : 62 /* Timer expired */ -ENOSR: Errno : 63 /* Out of streams resources */ -ENONET: Errno : 64 /* Machine is not on the network */ -ENOPKG: Errno : 65 /* Package not installed */ -EREMOTE: Errno : 66 /* Object is remote */ -ENOLINK: Errno : 67 /* Link has been severed */ -EADV: Errno : 68 /* Advertise error */ -ESRMNT: Errno : 69 /* Srmount error */ -ECOMM: Errno : 70 /* Communication error on send */ -EPROTO: Errno : 71 /* Protocol error */ -EMULTIHOP: Errno : 72 /* Multihop attempted */ -EDOTDOT: Errno : 73 /* RFS specific error */ -EBADMSG: Errno : 74 /* Not a data message */ -EOVERFLOW: Errno : 75 /* Value too large for defined data type */ -ENOTUNIQ: Errno : 76 /* Name not unique on network */ -EBADFD: Errno : 77 /* File descriptor in bad state */ -EREMCHG: Errno : 78 /* Remote address changed */ -ELIBACC: Errno : 79 /* Can not access a needed shared library */ -ELIBBAD: Errno : 80 /* Accessing a corrupted shared library */ -ELIBSCN: Errno : 81 /* .lib section in a.out corrupted */ -ELIBMAX: Errno : 82 /* Attempting to link in too many shared libraries */ -ELIBEXEC: Errno : 83 /* Cannot exec a shared library directly */ -EILSEQ: Errno : 84 /* Illegal byte sequence */ -ERESTART: Errno : 85 /* Interrupted system call should be restarted */ -ESTRPIPE: Errno : 86 /* Streams pipe error */ -EUSERS: Errno : 87 /* Too many users */ -ENOTSOCK: Errno : 88 /* Socket operation on non-socket */ -EDESTADDRREQ: Errno : 89 /* Destination address required */ -EMSGSIZE: Errno : 90 /* Message too long */ -EPROTOTYPE: Errno : 91 /* Protocol wrong type for socket */ -ENOPROTOOPT: Errno : 92 /* Protocol not available */ -EPROTONOSUPPORT:Errno : 93 /* Protocol not supported */ -ESOCKTNOSUPPORT:Errno : 94 /* Socket type not supported */ -EOPNOTSUPP: Errno : 95 /* Operation not supported on transport endpoint */ -EPFNOSUPPORT: Errno : 96 /* Protocol family not supported */ -EAFNOSUPPORT: Errno : 97 /* Address family not supported by protocol */ -EADDRINUSE: Errno : 98 /* Address already in use */ -EADDRNOTAVAIL: Errno : 99 /* Cannot assign requested address */ -ENETDOWN: Errno : 100 /* Network is down */ -ENETUNREACH: Errno : 101 /* Network is unreachable */ -ENETRESET: Errno : 102 /* Network dropped connection because of reset */ -ECONNABORTED: Errno : 103 /* Software caused connection abort */ -ECONNRESET: Errno : 104 /* Connection reset by peer */ -ENOBUFS: Errno : 105 /* No buffer space available */ -EISCONN: Errno : 106 /* Transport endpoint is already connected */ -ENOTCONN: Errno : 107 /* Transport endpoint is not connected */ -ESHUTDOWN: Errno : 108 /* Cannot send after transport endpoint shutdown */ -ETOOMANYREFS: Errno : 109 /* Too many references: cannot splice */ -ETIMEDOUT: Errno : 110 /* Connection timed out */ -ECONNREFUSED: Errno : 111 /* Connection refused */ -EHOSTDOWN: Errno : 112 /* Host is down */ -EHOSTUNREACH: Errno : 113 /* No route to host */ -EALREADY: Errno : 114 /* Operation already in progress */ -EINPROGRESS: Errno : 115 /* Operation now in progress */ -ESTALE: Errno : 116 /* Stale file handle */ -EUCLEAN: Errno : 117 /* Structure needs cleaning */ -ENOTNAM: Errno : 118 /* Not a XENIX named type file */ -ENAVAIL: Errno : 119 /* No XENIX semaphores available */ -EISNAM: Errno : 120 /* Is a named type file */ -EREMOTEIO: Errno : 121 /* Remote I/O error */ -EDQUOT: Errno : 122 /* Quota exceeded */ +ENOTEMPTY :: Platform_Error.ENOTEMPTY /* Directory not empty */ +ELOOP :: Platform_Error.ELOOP /* Too many symbolic links encountered */ +EWOULDBLOCK :: Platform_Error.EWOULDBLOCK /* Operation would block */ +ENOMSG :: Platform_Error.ENOMSG /* No message of desired type */ +EIDRM :: Platform_Error.EIDRM /* Identifier removed */ +ECHRNG :: Platform_Error.ECHRNG /* Channel number out of range */ +EL2NSYNC :: Platform_Error.EL2NSYNC /* Level 2 not synchronized */ +EL3HLT :: Platform_Error.EL3HLT /* Level 3 halted */ +EL3RST :: Platform_Error.EL3RST /* Level 3 reset */ +ELNRNG :: Platform_Error.ELNRNG /* Link number out of range */ +EUNATCH :: Platform_Error.EUNATCH /* Protocol driver not attached */ +ENOCSI :: Platform_Error.ENOCSI /* No CSI structure available */ +EL2HLT :: Platform_Error.EL2HLT /* Level 2 halted */ +EBADE :: Platform_Error.EBADE /* Invalid exchange */ +EBADR :: Platform_Error.EBADR /* Invalid request descriptor */ +EXFULL :: Platform_Error.EXFULL /* Exchange full */ +ENOANO :: Platform_Error.ENOANO /* No anode */ +EBADRQC :: Platform_Error.EBADRQC /* Invalid request code */ +EBADSLT :: Platform_Error.EBADSLT /* Invalid slot */ +EDEADLOCK :: Platform_Error.EDEADLOCK +EBFONT :: Platform_Error.EBFONT /* Bad font file format */ +ENOSTR :: Platform_Error.ENOSTR /* Device not a stream */ +ENODATA :: Platform_Error.ENODATA /* No data available */ +ETIME :: Platform_Error.ETIME /* Timer expired */ +ENOSR :: Platform_Error.ENOSR /* Out of streams resources */ +ENONET :: Platform_Error.ENONET /* Machine is not on the network */ +ENOPKG :: Platform_Error.ENOPKG /* Package not installed */ +EREMOTE :: Platform_Error.EREMOTE /* Object is remote */ +ENOLINK :: Platform_Error.ENOLINK /* Link has been severed */ +EADV :: Platform_Error.EADV /* Advertise error */ +ESRMNT :: Platform_Error.ESRMNT /* Srmount error */ +ECOMM :: Platform_Error.ECOMM /* Communication error on send */ +EPROTO :: Platform_Error.EPROTO /* Protocol error */ +EMULTIHOP :: Platform_Error.EMULTIHOP /* Multihop attempted */ +EDOTDOT :: Platform_Error.EDOTDOT /* RFS specific error */ +EBADMSG :: Platform_Error.EBADMSG /* Not a data message */ +EOVERFLOW :: Platform_Error.EOVERFLOW /* Value too large for defined data type */ +ENOTUNIQ :: Platform_Error.ENOTUNIQ /* Name not unique on network */ +EBADFD :: Platform_Error.EBADFD /* File descriptor in bad state */ +EREMCHG :: Platform_Error.EREMCHG /* Remote address changed */ +ELIBACC :: Platform_Error.ELIBACC /* Can not access a needed shared library */ +ELIBBAD :: Platform_Error.ELIBBAD /* Accessing a corrupted shared library */ +ELIBSCN :: Platform_Error.ELIBSCN /* .lib section in a.out corrupted */ +ELIBMAX :: Platform_Error.ELIBMAX /* Attempting to link in too many shared libraries */ +ELIBEXEC :: Platform_Error.ELIBEXEC /* Cannot exec a shared library directly */ +EILSEQ :: Platform_Error.EILSEQ /* Illegal byte sequence */ +ERESTART :: Platform_Error.ERESTART /* Interrupted system call should be restarted */ +ESTRPIPE :: Platform_Error.ESTRPIPE /* Streams pipe error */ +EUSERS :: Platform_Error.EUSERS /* Too many users */ +ENOTSOCK :: Platform_Error.ENOTSOCK /* Socket operation on non-socket */ +EDESTADDRREQ :: Platform_Error.EDESTADDRREQ /* Destination address required */ +EMSGSIZE :: Platform_Error.EMSGSIZE /* Message too long */ +EPROTOTYPE :: Platform_Error.EPROTOTYPE /* Protocol wrong type for socket */ +ENOPROTOOPT :: Platform_Error.ENOPROTOOPT /* Protocol not available */ +EPROTONOSUPPOR :: Platform_Error.EPROTONOSUPPORT /* Protocol not supported */ +ESOCKTNOSUPPOR :: Platform_Error.ESOCKTNOSUPPORT /* Socket type not supported */ +EOPNOTSUPP :: Platform_Error.EOPNOTSUPP /* Operation not supported on transport endpoint */ +EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT /* Protocol family not supported */ +EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT /* Address family not supported by protocol */ +EADDRINUSE :: Platform_Error.EADDRINUSE /* Address already in use */ +EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL /* Cannot assign requested address */ +ENETDOWN :: Platform_Error.ENETDOWN /* Network is down */ +ENETUNREACH :: Platform_Error.ENETUNREACH /* Network is unreachable */ +ENETRESET :: Platform_Error.ENETRESET /* Network dropped connection because of reset */ +ECONNABORTED :: Platform_Error.ECONNABORTED /* Software caused connection abort */ +ECONNRESET :: Platform_Error.ECONNRESET /* Connection reset by peer */ +ENOBUFS :: Platform_Error.ENOBUFS /* No buffer space available */ +EISCONN :: Platform_Error.EISCONN /* Transport endpoint is already connected */ +ENOTCONN :: Platform_Error.ENOTCONN /* Transport endpoint is not connected */ +ESHUTDOWN :: Platform_Error.ESHUTDOWN /* Cannot send after transport endpoint shutdown */ +ETOOMANYREFS :: Platform_Error.ETOOMANYREFS /* Too many references: cannot splice */ +ETIMEDOUT :: Platform_Error.ETIMEDOUT /* Connection timed out */ +ECONNREFUSED :: Platform_Error.ECONNREFUSED /* Connection refused */ +EHOSTDOWN :: Platform_Error.EHOSTDOWN /* Host is down */ +EHOSTUNREACH :: Platform_Error.EHOSTUNREACH /* No route to host */ +EALREADY :: Platform_Error.EALREADY /* Operation already in progress */ +EINPROGRESS :: Platform_Error.EINPROGRESS /* Operation now in progress */ +ESTALE :: Platform_Error.ESTALE /* Stale file handle */ +EUCLEAN :: Platform_Error.EUCLEAN /* Structure needs cleaning */ +ENOTNAM :: Platform_Error.ENOTNAM /* Not a XENIX named type file */ +ENAVAIL :: Platform_Error.ENAVAIL /* No XENIX semaphores available */ +EISNAM :: Platform_Error.EISNAM /* Is a named type file */ +EREMOTEIO :: Platform_Error.EREMOTEIO /* Remote I/O error */ +EDQUOT :: Platform_Error.EDQUOT /* Quota exceeded */ -ENOMEDIUM: Errno : 123 /* No medium found */ -EMEDIUMTYPE: Errno : 124 /* Wrong medium type */ -ECANCELED: Errno : 125 /* Operation Canceled */ -ENOKEY: Errno : 126 /* Required key not available */ -EKEYEXPIRED: Errno : 127 /* Key has expired */ -EKEYREVOKED: Errno : 128 /* Key has been revoked */ -EKEYREJECTED: Errno : 129 /* Key was rejected by service */ +ENOMEDIUM :: Platform_Error.ENOMEDIUM /* No medium found */ +EMEDIUMTYPE :: Platform_Error.EMEDIUMTYPE /* Wrong medium type */ +ECANCELED :: Platform_Error.ECANCELED /* Operation Canceled */ +ENOKEY :: Platform_Error.ENOKEY /* Required key not available */ +EKEYEXPIRED :: Platform_Error.EKEYEXPIRED /* Key has expired */ +EKEYREVOKED :: Platform_Error.EKEYREVOKED /* Key has been revoked */ +EKEYREJECTED :: Platform_Error.EKEYREJECTED /* Key was rejected by service */ /* for robust mutexes */ -EOWNERDEAD: Errno : 130 /* Owner died */ -ENOTRECOVERABLE: Errno : 131 /* State not recoverable */ +EOWNERDEAD :: Platform_Error.EOWNERDEAD /* Owner died */ +ENOTRECOVERABLE :: Platform_Error.ENOTRECOVERABLE /* State not recoverable */ -ERFKILL: Errno : 132 /* Operation not possible due to RF-kill */ +ERFKILL :: Platform_Error.ERFKILL /* Operation not possible due to RF-kill */ -EHWPOISON: Errno : 133 /* Memory page has hardware error */ +EHWPOISON :: Platform_Error.EHWPOISON /* Memory page has hardware error */ ADDR_NO_RANDOMIZE :: 0x40000 @@ -520,8 +520,8 @@ _get_errno :: proc(res: int) -> Errno { } // get errno from libc -get_last_error :: proc "contextless" () -> int { - return int(__errno_location()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__errno_location()^) } personality :: proc(persona: u64) -> (Errno) { diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index da34a4168..b27daac3a 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -9,148 +9,287 @@ import "core:c" Handle :: distinct i32 File_Time :: distinct u64 -Errno :: distinct i32 INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno : 0 /* No error */ -EPERM: Errno : 1 /* Operation not permitted */ -ENOENT: Errno : 2 /* No such file or directory */ -EINTR: Errno : 4 /* Interrupted system call */ -ESRCH: Errno : 3 /* No such process */ -EIO: Errno : 5 /* Input/output error */ -ENXIO: Errno : 6 /* Device not configured */ -E2BIG: Errno : 7 /* Argument list too long */ -ENOEXEC: Errno : 8 /* Exec format error */ -EBADF: Errno : 9 /* Bad file descriptor */ -ECHILD: Errno : 10 /* No child processes */ -EDEADLK: Errno : 11 /* Resource deadlock avoided. 11 was EAGAIN */ -ENOMEM: Errno : 12 /* Cannot allocate memory */ -EACCES: Errno : 13 /* Permission denied */ -EFAULT: Errno : 14 /* Bad address */ -ENOTBLK: Errno : 15 /* Block device required */ -EBUSY: Errno : 16 /* Device busy */ -EEXIST: Errno : 17 /* File exists */ -EXDEV: Errno : 18 /* Cross-device link */ -ENODEV: Errno : 19 /* Operation not supported by device */ -ENOTDIR: Errno : 20 /* Not a directory */ -EISDIR: Errno : 21 /* Is a directory */ -EINVAL: Errno : 22 /* Invalid argument */ -ENFILE: Errno : 23 /* Too many open files in system */ -EMFILE: Errno : 24 /* Too many open files */ -ENOTTY: Errno : 25 /* Inappropriate ioctl for device */ -ETXTBSY: Errno : 26 /* Text file busy */ -EFBIG: Errno : 27 /* File too large */ -ENOSPC: Errno : 28 /* No space left on device */ -ESPIPE: Errno : 29 /* Illegal seek */ -EROFS: Errno : 30 /* Read-only file system */ -EMLINK: Errno : 31 /* Too many links */ -EPIPE: Errno : 32 /* Broken pipe */ +_Platform_Error :: enum i32 { + NONE = 0, + EPERM = 1, /* Operation not permitted */ + ENOENT = 2, /* No such file or directory */ + EINTR = 4, /* Interrupted system call */ + ESRCH = 3, /* No such process */ + EIO = 5, /* Input/output error */ + ENXIO = 6, /* Device not configured */ + E2BIG = 7, /* Argument list too long */ + ENOEXEC = 8, /* Exec format error */ + EBADF = 9, /* Bad file descriptor */ + ECHILD = 10, /* No child processes */ + EDEADLK = 11, /* Resource deadlock avoided. 11 was EAGAIN */ + ENOMEM = 12, /* Cannot allocate memory */ + EACCES = 13, /* Permission denied */ + EFAULT = 14, /* Bad address */ + ENOTBLK = 15, /* Block device required */ + EBUSY = 16, /* Device busy */ + EEXIST = 17, /* File exists */ + EXDEV = 18, /* Cross-device link */ + ENODEV = 19, /* Operation not supported by device */ + ENOTDIR = 20, /* Not a directory */ + EISDIR = 21, /* Is a directory */ + EINVAL = 22, /* Invalid argument */ + ENFILE = 23, /* Too many open files in system */ + EMFILE = 24, /* Too many open files */ + ENOTTY = 25, /* Inappropriate ioctl for device */ + ETXTBSY = 26, /* Text file busy */ + EFBIG = 27, /* File too large */ + ENOSPC = 28, /* No space left on device */ + ESPIPE = 29, /* Illegal seek */ + EROFS = 30, /* Read-only file system */ + EMLINK = 31, /* Too many links */ + EPIPE = 32, /* Broken pipe */ + + /* math software */ + EDOM = 33, /* Numerical argument out of domain */ + ERANGE = 34, /* Result too large or too small */ + + /* non-blocking and interrupt i/o */ + EAGAIN = 35, /* Resource temporarily unavailable */ + EWOULDBLOCK = EAGAIN, /* Operation would block */ + EINPROGRESS = 36, /* Operation now in progress */ + EALREADY = 37, /* Operation already in progress */ + + /* ipc/network software -- argument errors */ + ENOTSOCK = 38, /* Socket operation on non-socket */ + EDESTADDRREQ = 39, /* Destination address required */ + EMSGSIZE = 40, /* Message too long */ + EPROTOTYPE = 41, /* Protocol wrong type for socket */ + ENOPROTOOPT = 42, /* Protocol option not available */ + EPROTONOSUPPORT = 43, /* Protocol not supported */ + ESOCKTNOSUPPORT = 44, /* Socket type not supported */ + EOPNOTSUPP = 45, /* Operation not supported */ + EPFNOSUPPORT = 46, /* Protocol family not supported */ + EAFNOSUPPORT = 47, /* Address family not supported by protocol family */ + EADDRINUSE = 48, /* Address already in use */ + EADDRNOTAVAIL = 49, /* Can't assign requested address */ + + /* ipc/network software -- operational errors */ + ENETDOWN = 50, /* Network is down */ + ENETUNREACH = 51, /* Network is unreachable */ + ENETRESET = 52, /* Network dropped connection on reset */ + ECONNABORTED = 53, /* Software caused connection abort */ + ECONNRESET = 54, /* Connection reset by peer */ + ENOBUFS = 55, /* No buffer space available */ + EISCONN = 56, /* Socket is already connected */ + ENOTCONN = 57, /* Socket is not connected */ + ESHUTDOWN = 58, /* Can't send after socket shutdown */ + ETOOMANYREFS = 59, /* Too many references: can't splice */ + ETIMEDOUT = 60, /* Operation timed out */ + ECONNREFUSED = 61, /* Connection refused */ + + ELOOP = 62, /* Too many levels of symbolic links */ + ENAMETOOLONG = 63, /* File name too long */ + + /* should be rearranged */ + EHOSTDOWN = 64, /* Host is down */ + EHOSTUNREACH = 65, /* No route to host */ + ENOTEMPTY = 66, /* Directory not empty */ + + /* quotas & mush */ + EPROCLIM = 67, /* Too many processes */ + EUSERS = 68, /* Too many users */ + EDQUOT = 69, /* Disc quota exceeded */ + + /* Network File System */ + ESTALE = 70, /* Stale NFS file handle */ + EREMOTE = 71, /* Too many levels of remote in path */ + EBADRPC = 72, /* RPC struct is bad */ + ERPCMISMATCH = 73, /* RPC version wrong */ + EPROGUNAVAIL = 74, /* RPC prog. not avail */ + EPROGMISMATCH = 75, /* Program version wrong */ + EPROCUNAVAIL = 76, /* Bad procedure for program */ + + ENOLCK = 77, /* No locks available */ + ENOSYS = 78, /* Function not implemented */ + + EFTYPE = 79, /* Inappropriate file type or format */ + EAUTH = 80, /* Authentication error */ + ENEEDAUTH = 81, /* Need authenticator */ + + /* SystemV IPC */ + EIDRM = 82, /* Identifier removed */ + ENOMSG = 83, /* No message of desired type */ + EOVERFLOW = 84, /* Value too large to be stored in data type */ + + /* Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 */ + EILSEQ = 85, /* Illegal byte sequence */ + + /* From IEEE Std 1003.1-2001 */ + /* Base, Realtime, Threads or Thread Priority Scheduling option errors */ + ENOTSUP = 86, /* Not supported */ + + /* Realtime option errors */ + ECANCELED = 87, /* Operation canceled */ + + /* Realtime, XSI STREAMS option errors */ + EBADMSG = 88, /* Bad or Corrupt message */ + + /* XSI STREAMS option errors */ + ENODATA = 89, /* No message available */ + ENOSR = 90, /* No STREAM resources */ + ENOSTR = 91, /* Not a STREAM */ + ETIME = 92, /* STREAM ioctl timeout */ + + /* File system extended attribute errors */ + ENOATTR = 93, /* Attribute not found */ + + /* Realtime, XSI STREAMS option errors */ + EMULTIHOP = 94, /* Multihop attempted */ + ENOLINK = 95, /* Link has been severed */ + EPROTO = 96, /* Protocol error */ + + /* Robust mutexes */ + EOWNERDEAD = 97, /* Previous owner died */ + ENOTRECOVERABLE = 98, /* State not recoverable */ + + ELAST = 98, /* Must equal largest errno */ +} + +EPERM :: Platform_Error.EPERM /* Operation not permitted */ +ENOENT :: Platform_Error.ENOENT /* No such file or directory */ +EINTR :: Platform_Error.EINTR /* Interrupted system call */ +ESRCH :: Platform_Error.ESRCH /* No such process */ +EIO :: Platform_Error.EIO /* Input/output error */ +ENXIO :: Platform_Error.ENXIO /* Device not configured */ +E2BIG :: Platform_Error.E2BIG /* Argument list too long */ +ENOEXEC :: Platform_Error.ENOEXEC /* Exec format error */ +EBADF :: Platform_Error.EBADF /* Bad file descriptor */ +ECHILD :: Platform_Error.ECHILD /* No child processes */ +EDEADLK :: Platform_Error.EDEADLK /* Resource deadlock avoided. 11 was EAGAIN */ +ENOMEM :: Platform_Error.ENOMEM /* Cannot allocate memory */ +EACCES :: Platform_Error.EACCES /* Permission denied */ +EFAULT :: Platform_Error.EFAULT /* Bad address */ +ENOTBLK :: Platform_Error.ENOTBLK /* Block device required */ +EBUSY :: Platform_Error.EBUSY /* Device busy */ +EEXIST :: Platform_Error.EEXIST /* File exists */ +EXDEV :: Platform_Error.EXDEV /* Cross-device link */ +ENODEV :: Platform_Error.ENODEV /* Operation not supported by device */ +ENOTDIR :: Platform_Error.ENOTDIR /* Not a directory */ +EISDIR :: Platform_Error.EISDIR /* Is a directory */ +EINVAL :: Platform_Error.EINVAL /* Invalid argument */ +ENFILE :: Platform_Error.ENFILE /* Too many open files in system */ +EMFILE :: Platform_Error.EMFILE /* Too many open files */ +ENOTTY :: Platform_Error.ENOTTY /* Inappropriate ioctl for device */ +ETXTBSY :: Platform_Error.ETXTBSY /* Text file busy */ +EFBIG :: Platform_Error.EFBIG /* File too large */ +ENOSPC :: Platform_Error.ENOSPC /* No space left on device */ +ESPIPE :: Platform_Error.ESPIPE /* Illegal seek */ +EROFS :: Platform_Error.EROFS /* Read-only file system */ +EMLINK :: Platform_Error.EMLINK /* Too many links */ +EPIPE :: Platform_Error.EPIPE /* Broken pipe */ /* math software */ -EDOM: Errno : 33 /* Numerical argument out of domain */ -ERANGE: Errno : 34 /* Result too large or too small */ +EDOM :: Platform_Error.EDOM /* Numerical argument out of domain */ +ERANGE :: Platform_Error.ERANGE /* Result too large or too small */ /* non-blocking and interrupt i/o */ -EAGAIN: Errno : 35 /* Resource temporarily unavailable */ -EWOULDBLOCK: Errno : EAGAIN /* Operation would block */ -EINPROGRESS: Errno : 36 /* Operation now in progress */ -EALREADY: Errno : 37 /* Operation already in progress */ +EAGAIN :: Platform_Error.EAGAIN /* Resource temporarily unavailable */ +EWOULDBLOCK :: EAGAIN /* Operation would block */ +EINPROGRESS :: Platform_Error.EINPROGRESS /* Operation now in progress */ +EALREADY :: Platform_Error.EALREADY /* Operation already in progress */ /* ipc/network software -- argument errors */ -ENOTSOCK: Errno : 38 /* Socket operation on non-socket */ -EDESTADDRREQ: Errno : 39 /* Destination address required */ -EMSGSIZE: Errno : 40 /* Message too long */ -EPROTOTYPE: Errno : 41 /* Protocol wrong type for socket */ -ENOPROTOOPT: Errno : 42 /* Protocol option not available */ -EPROTONOSUPPORT: Errno : 43 /* Protocol not supported */ -ESOCKTNOSUPPORT: Errno : 44 /* Socket type not supported */ -EOPNOTSUPP: Errno : 45 /* Operation not supported */ -EPFNOSUPPORT: Errno : 46 /* Protocol family not supported */ -EAFNOSUPPORT: Errno : 47 /* Address family not supported by protocol family */ -EADDRINUSE: Errno : 48 /* Address already in use */ -EADDRNOTAVAIL: Errno : 49 /* Can't assign requested address */ +ENOTSOCK :: Platform_Error.ENOTSOCK /* Socket operation on non-socket */ +EDESTADDRREQ :: Platform_Error.EDESTADDRREQ /* Destination address required */ +EMSGSIZE :: Platform_Error.EMSGSIZE /* Message too long */ +EPROTOTYPE :: Platform_Error.EPROTOTYPE /* Protocol wrong type for socket */ +ENOPROTOOPT :: Platform_Error.ENOPROTOOPT /* Protocol option not available */ +EPROTONOSUPPORT :: Platform_Error.EPROTONOSUPPORT /* Protocol not supported */ +ESOCKTNOSUPPORT :: Platform_Error.ESOCKTNOSUPPORT /* Socket type not supported */ +EOPNOTSUPP :: Platform_Error.EOPNOTSUPP /* Operation not supported */ +EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT /* Protocol family not supported */ +EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT /* Address family not supported by protocol family */ +EADDRINUSE :: Platform_Error.EADDRINUSE /* Address already in use */ +EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL /* Can't assign requested address */ /* ipc/network software -- operational errors */ -ENETDOWN: Errno : 50 /* Network is down */ -ENETUNREACH: Errno : 51 /* Network is unreachable */ -ENETRESET: Errno : 52 /* Network dropped connection on reset */ -ECONNABORTED: Errno : 53 /* Software caused connection abort */ -ECONNRESET: Errno : 54 /* Connection reset by peer */ -ENOBUFS: Errno : 55 /* No buffer space available */ -EISCONN: Errno : 56 /* Socket is already connected */ -ENOTCONN: Errno : 57 /* Socket is not connected */ -ESHUTDOWN: Errno : 58 /* Can't send after socket shutdown */ -ETOOMANYREFS: Errno : 59 /* Too many references: can't splice */ -ETIMEDOUT: Errno : 60 /* Operation timed out */ -ECONNREFUSED: Errno : 61 /* Connection refused */ +ENETDOWN :: Platform_Error.ENETDOWN /* Network is down */ +ENETUNREACH :: Platform_Error.ENETUNREACH /* Network is unreachable */ +ENETRESET :: Platform_Error.ENETRESET /* Network dropped connection on reset */ +ECONNABORTED :: Platform_Error.ECONNABORTED /* Software caused connection abort */ +ECONNRESET :: Platform_Error.ECONNRESET /* Connection reset by peer */ +ENOBUFS :: Platform_Error.ENOBUFS /* No buffer space available */ +EISCONN :: Platform_Error.EISCONN /* Socket is already connected */ +ENOTCONN :: Platform_Error.ENOTCONN /* Socket is not connected */ +ESHUTDOWN :: Platform_Error.ESHUTDOWN /* Can't send after socket shutdown */ +ETOOMANYREFS :: Platform_Error.ETOOMANYREFS /* Too many references: can't splice */ +ETIMEDOUT :: Platform_Error.ETIMEDOUT /* Operation timed out */ +ECONNREFUSED :: Platform_Error.ECONNREFUSED /* Connection refused */ -ELOOP: Errno : 62 /* Too many levels of symbolic links */ -ENAMETOOLONG: Errno : 63 /* File name too long */ +ELOOP :: Platform_Error.ELOOP /* Too many levels of symbolic links */ +ENAMETOOLONG :: Platform_Error.ENAMETOOLONG /* File name too long */ /* should be rearranged */ -EHOSTDOWN: Errno : 64 /* Host is down */ -EHOSTUNREACH: Errno : 65 /* No route to host */ -ENOTEMPTY: Errno : 66 /* Directory not empty */ +EHOSTDOWN :: Platform_Error.EHOSTDOWN /* Host is down */ +EHOSTUNREACH :: Platform_Error.EHOSTUNREACH /* No route to host */ +ENOTEMPTY :: Platform_Error.ENOTEMPTY /* Directory not empty */ /* quotas & mush */ -EPROCLIM: Errno : 67 /* Too many processes */ -EUSERS: Errno : 68 /* Too many users */ -EDQUOT: Errno : 69 /* Disc quota exceeded */ +EPROCLIM :: Platform_Error.EPROCLIM /* Too many processes */ +EUSERS :: Platform_Error.EUSERS /* Too many users */ +EDQUOT :: Platform_Error.EDQUOT /* Disc quota exceeded */ /* Network File System */ -ESTALE: Errno : 70 /* Stale NFS file handle */ -EREMOTE: Errno : 71 /* Too many levels of remote in path */ -EBADRPC: Errno : 72 /* RPC struct is bad */ -ERPCMISMATCH: Errno : 73 /* RPC version wrong */ -EPROGUNAVAIL: Errno : 74 /* RPC prog. not avail */ -EPROGMISMATCH: Errno : 75 /* Program version wrong */ -EPROCUNAVAIL: Errno : 76 /* Bad procedure for program */ +ESTALE :: Platform_Error.ESTALE /* Stale NFS file handle */ +EREMOTE :: Platform_Error.EREMOTE /* Too many levels of remote in path */ +EBADRPC :: Platform_Error.EBADRPC /* RPC struct is bad */ +ERPCMISMATCH :: Platform_Error.ERPCMISMATCH /* RPC version wrong */ +EPROGUNAVAIL :: Platform_Error.EPROGUNAVAIL /* RPC prog. not avail */ +EPROGMISMATCH :: Platform_Error.EPROGMISMATCH /* Program version wrong */ +EPROCUNAVAIL :: Platform_Error.EPROCUNAVAIL /* Bad procedure for program */ -ENOLCK: Errno : 77 /* No locks available */ -ENOSYS: Errno : 78 /* Function not implemented */ +ENOLCK :: Platform_Error.ENOLCK /* No locks available */ +ENOSYS :: Platform_Error.ENOSYS /* Function not implemented */ -EFTYPE: Errno : 79 /* Inappropriate file type or format */ -EAUTH: Errno : 80 /* Authentication error */ -ENEEDAUTH: Errno : 81 /* Need authenticator */ +EFTYPE :: Platform_Error.EFTYPE /* Inappropriate file type or format */ +EAUTH :: Platform_Error.EAUTH /* Authentication error */ +ENEEDAUTH :: Platform_Error.ENEEDAUTH /* Need authenticator */ /* SystemV IPC */ -EIDRM: Errno : 82 /* Identifier removed */ -ENOMSG: Errno : 83 /* No message of desired type */ -EOVERFLOW: Errno : 84 /* Value too large to be stored in data type */ +EIDRM :: Platform_Error.EIDRM /* Identifier removed */ +ENOMSG :: Platform_Error.ENOMSG /* No message of desired type */ +EOVERFLOW :: Platform_Error.EOVERFLOW /* Value too large to be stored in data type */ /* Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 */ -EILSEQ: Errno : 85 /* Illegal byte sequence */ +EILSEQ :: Platform_Error.EILSEQ /* Illegal byte sequence */ /* From IEEE Std 1003.1-2001 */ /* Base, Realtime, Threads or Thread Priority Scheduling option errors */ -ENOTSUP: Errno : 86 /* Not supported */ +ENOTSUP :: Platform_Error.ENOTSUP /* Not supported */ /* Realtime option errors */ -ECANCELED: Errno : 87 /* Operation canceled */ +ECANCELED :: Platform_Error.ECANCELED /* Operation canceled */ /* Realtime, XSI STREAMS option errors */ -EBADMSG: Errno : 88 /* Bad or Corrupt message */ +EBADMSG :: Platform_Error.EBADMSG /* Bad or Corrupt message */ /* XSI STREAMS option errors */ -ENODATA: Errno : 89 /* No message available */ -ENOSR: Errno : 90 /* No STREAM resources */ -ENOSTR: Errno : 91 /* Not a STREAM */ -ETIME: Errno : 92 /* STREAM ioctl timeout */ +ENODATA :: Platform_Error.ENODATA /* No message available */ +ENOSR :: Platform_Error.ENOSR /* No STREAM resources */ +ENOSTR :: Platform_Error.ENOSTR /* Not a STREAM */ +ETIME :: Platform_Error.ETIME /* STREAM ioctl timeout */ /* File system extended attribute errors */ -ENOATTR: Errno : 93 /* Attribute not found */ +ENOATTR :: Platform_Error.ENOATTR /* Attribute not found */ /* Realtime, XSI STREAMS option errors */ -EMULTIHOP: Errno : 94 /* Multihop attempted */ -ENOLINK: Errno : 95 /* Link has been severed */ -EPROTO: Errno : 96 /* Protocol error */ +EMULTIHOP :: Platform_Error.EMULTIHOP /* Multihop attempted */ +ENOLINK :: Platform_Error.ENOLINK /* Link has been severed */ +EPROTO :: Platform_Error.EPROTO /* Protocol error */ /* Robust mutexes */ -EOWNERDEAD: Errno : 97 /* Previous owner died */ -ENOTRECOVERABLE: Errno : 98 /* State not recoverable */ +EOWNERDEAD :: Platform_Error.EOWNERDEAD /* Previous owner died */ +ENOTRECOVERABLE :: Platform_Error.ENOTRECOVERABLE /* State not recoverable */ -ELAST: Errno : 98 /* Must equal largest errno */ +ELAST :: Platform_Error.ELAST /* Must equal largest errno */ /* end of errno */ @@ -338,8 +477,8 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } -get_last_error :: proc "contextless" () -> int { - return int(__errno_location()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__errno_location()^) } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index a3b74a524..cc7642387 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -9,108 +9,205 @@ import "base:runtime" Handle :: distinct i32 Pid :: distinct i32 File_Time :: distinct u64 -Errno :: distinct i32 INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno: 0 +_Platform_Error :: enum i32 { + NONE = 0, + EPERM = 1, + ENOENT = 2, + ESRCH = 3, + EINTR = 4, + EIO = 5, + ENXIO = 6, + E2BIG = 7, + ENOEXEC = 8, + EBADF = 9, + ECHILD = 10, + EDEADLK = 11, + ENOMEM = 12, + EACCES = 13, + EFAULT = 14, + ENOTBLK = 15, + EBUSY = 16, + EEXIST = 17, + EXDEV = 18, + ENODEV = 19, + ENOTDIR = 20, + EISDIR = 21, + EINVAL = 22, + ENFILE = 23, + EMFILE = 24, + ENOTTY = 25, + ETXTBSY = 26, + EFBIG = 27, + ENOSPC = 28, + ESPIPE = 29, + EROFS = 30, + EMLINK = 31, + EPIPE = 32, + EDOM = 33, + ERANGE = 34, + EAGAIN = 35, + EWOULDBLOCK = EAGAIN, + EINPROGRESS = 36, + EALREADY = 37, + ENOTSOCK = 38, + EDESTADDRREQ = 39, + EMSGSIZE = 40, + EPROTOTYPE = 41, + ENOPROTOOPT = 42, + EPROTONOSUPPORT = 43, + ESOCKTNOSUPPORT = 44, + EOPNOTSUPP = 45, + EPFNOSUPPORT = 46, + EAFNOSUPPORT = 47, + EADDRINUSE = 48, + EADDRNOTAVAIL = 49, + ENETDOWN = 50, + ENETUNREACH = 51, + ENETRESET = 52, + ECONNABORTED = 53, + ECONNRESET = 54, + ENOBUFS = 55, + EISCONN = 56, + ENOTCONN = 57, + ESHUTDOWN = 58, + ETOOMANYREFS = 59, + ETIMEDOUT = 60, + ECONNREFUSED = 61, + ELOOP = 62, + ENAMETOOLONG = 63, + EHOSTDOWN = 64, + EHOSTUNREACH = 65, + ENOTEMPTY = 66, + EPROCLIM = 67, + EUSERS = 68, + EDQUOT = 69, + ESTALE = 70, + EREMOTE = 71, + EBADRPC = 72, + ERPCMISMATCH = 73, + EPROGUNAVAIL = 74, + EPROGMISMATCH = 75, + EPROCUNAVAIL = 76, + ENOLCK = 77, + ENOSYS = 78, + EFTYPE = 79, + EAUTH = 80, + ENEEDAUTH = 81, + EIPSEC = 82, + ENOATTR = 83, + EILSEQ = 84, + ENOMEDIUM = 85, + EMEDIUMTYPE = 86, + EOVERFLOW = 87, + ECANCELED = 88, + EIDRM = 89, + ENOMSG = 90, + ENOTSUP = 91, + EBADMSG = 92, + ENOTRECOVERABLE = 93, + EOWNERDEAD = 94, + EPROTO = 95, +} -EPERM: Errno: 1 -ENOENT: Errno: 2 -ESRCH: Errno: 3 -EINTR: Errno: 4 -EIO: Errno: 5 -ENXIO: Errno: 6 -E2BIG: Errno: 7 -ENOEXEC: Errno: 8 -EBADF: Errno: 9 -ECHILD: Errno: 10 -EDEADLK: Errno: 11 -ENOMEM: Errno: 12 -EACCES: Errno: 13 -EFAULT: Errno: 14 -ENOTBLK: Errno: 15 -EBUSY: Errno: 16 -EEXIST: Errno: 17 -EXDEV: Errno: 18 -ENODEV: Errno: 19 -ENOTDIR: Errno: 20 -EISDIR: Errno: 21 -EINVAL: Errno: 22 -ENFILE: Errno: 23 -EMFILE: Errno: 24 -ENOTTY: Errno: 25 -ETXTBSY: Errno: 26 -EFBIG: Errno: 27 -ENOSPC: Errno: 28 -ESPIPE: Errno: 29 -EROFS: Errno: 30 -EMLINK: Errno: 31 -EPIPE: Errno: 32 -EDOM: Errno: 33 -ERANGE: Errno: 34 -EAGAIN: Errno: 35 -EWOULDBLOCK: Errno: EAGAIN -EINPROGRESS: Errno: 36 -EALREADY: Errno: 37 -ENOTSOCK: Errno: 38 -EDESTADDRREQ: Errno: 39 -EMSGSIZE: Errno: 40 -EPROTOTYPE: Errno: 41 -ENOPROTOOPT: Errno: 42 -EPROTONOSUPPORT: Errno: 43 -ESOCKTNOSUPPORT: Errno: 44 -EOPNOTSUPP: Errno: 45 -EPFNOSUPPORT: Errno: 46 -EAFNOSUPPORT: Errno: 47 -EADDRINUSE: Errno: 48 -EADDRNOTAVAIL: Errno: 49 -ENETDOWN: Errno: 50 -ENETUNREACH: Errno: 51 -ENETRESET: Errno: 52 -ECONNABORTED: Errno: 53 -ECONNRESET: Errno: 54 -ENOBUFS: Errno: 55 -EISCONN: Errno: 56 -ENOTCONN: Errno: 57 -ESHUTDOWN: Errno: 58 -ETOOMANYREFS: Errno: 59 -ETIMEDOUT: Errno: 60 -ECONNREFUSED: Errno: 61 -ELOOP: Errno: 62 -ENAMETOOLONG: Errno: 63 -EHOSTDOWN: Errno: 64 -EHOSTUNREACH: Errno: 65 -ENOTEMPTY: Errno: 66 -EPROCLIM: Errno: 67 -EUSERS: Errno: 68 -EDQUOT: Errno: 69 -ESTALE: Errno: 70 -EREMOTE: Errno: 71 -EBADRPC: Errno: 72 -ERPCMISMATCH: Errno: 73 -EPROGUNAVAIL: Errno: 74 -EPROGMISMATCH: Errno: 75 -EPROCUNAVAIL: Errno: 76 -ENOLCK: Errno: 77 -ENOSYS: Errno: 78 -EFTYPE: Errno: 79 -EAUTH: Errno: 80 -ENEEDAUTH: Errno: 81 -EIPSEC: Errno: 82 -ENOATTR: Errno: 83 -EILSEQ: Errno: 84 -ENOMEDIUM: Errno: 85 -EMEDIUMTYPE: Errno: 86 -EOVERFLOW: Errno: 87 -ECANCELED: Errno: 88 -EIDRM: Errno: 89 -ENOMSG: Errno: 90 -ENOTSUP: Errno: 91 -EBADMSG: Errno: 92 -ENOTRECOVERABLE: Errno: 93 -EOWNERDEAD: Errno: 94 -EPROTO: Errno: 95 +EPERM :: Platform_Error.EPERM +ENOENT :: Platform_Error.ENOENT +ESRCH :: Platform_Error.ESRCH +EINTR :: Platform_Error.EINTR +EIO :: Platform_Error.EIO +ENXIO :: Platform_Error.ENXIO +E2BIG :: Platform_Error.E2BIG +ENOEXEC :: Platform_Error.ENOEXEC +EBADF :: Platform_Error.EBADF +ECHILD :: Platform_Error.ECHILD +EDEADLK :: Platform_Error.EDEADLK +ENOMEM :: Platform_Error.ENOMEM +EACCES :: Platform_Error.EACCES +EFAULT :: Platform_Error.EFAULT +ENOTBLK :: Platform_Error.ENOTBLK +EBUSY :: Platform_Error.EBUSY +EEXIST :: Platform_Error.EEXIST +EXDEV :: Platform_Error.EXDEV +ENODEV :: Platform_Error.ENODEV +ENOTDIR :: Platform_Error.ENOTDIR +EISDIR :: Platform_Error.EISDIR +EINVAL :: Platform_Error.EINVAL +ENFILE :: Platform_Error.ENFILE +EMFILE :: Platform_Error.EMFILE +ENOTTY :: Platform_Error.ENOTTY +ETXTBSY :: Platform_Error.ETXTBSY +EFBIG :: Platform_Error.EFBIG +ENOSPC :: Platform_Error.ENOSPC +ESPIPE :: Platform_Error.ESPIPE +EROFS :: Platform_Error.EROFS +EMLINK :: Platform_Error.EMLINK +EPIPE :: Platform_Error.EPIPE +EDOM :: Platform_Error.EDOM +ERANGE :: Platform_Error.ERANGE +EAGAIN :: Platform_Error.EAGAIN +EWOULDBLOCK :: Platform_Error.EWOULDBLOCK +EINPROGRESS :: Platform_Error.EINPROGRESS +EALREADY :: Platform_Error.EALREADY +ENOTSOCK :: Platform_Error.ENOTSOCK +EDESTADDRREQ :: Platform_Error.EDESTADDRREQ +EMSGSIZE :: Platform_Error.EMSGSIZE +EPROTOTYPE :: Platform_Error.EPROTOTYPE +ENOPROTOOPT :: Platform_Error.ENOPROTOOPT +EPROTONOSUPPORT :: Platform_Error.EPROTONOSUPPORT +ESOCKTNOSUPPORT :: Platform_Error.ESOCKTNOSUPPORT +EOPNOTSUPP :: Platform_Error.EOPNOTSUPP +EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT +EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT +EADDRINUSE :: Platform_Error.EADDRINUSE +EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL +ENETDOWN :: Platform_Error.ENETDOWN +ENETUNREACH :: Platform_Error.ENETUNREACH +ENETRESET :: Platform_Error.ENETRESET +ECONNABORTED :: Platform_Error.ECONNABORTED +ECONNRESET :: Platform_Error.ECONNRESET +ENOBUFS :: Platform_Error.ENOBUFS +EISCONN :: Platform_Error.EISCONN +ENOTCONN :: Platform_Error.ENOTCONN +ESHUTDOWN :: Platform_Error.ESHUTDOWN +ETOOMANYREFS :: Platform_Error.ETOOMANYREFS +ETIMEDOUT :: Platform_Error.ETIMEDOUT +ECONNREFUSED :: Platform_Error.ECONNREFUSED +ELOOP :: Platform_Error.ELOOP +ENAMETOOLONG :: Platform_Error.ENAMETOOLONG +EHOSTDOWN :: Platform_Error.EHOSTDOWN +EHOSTUNREACH :: Platform_Error.EHOSTUNREACH +ENOTEMPTY :: Platform_Error.ENOTEMPTY +EPROCLIM :: Platform_Error.EPROCLIM +EUSERS :: Platform_Error.EUSERS +EDQUOT :: Platform_Error.EDQUOT +ESTALE :: Platform_Error.ESTALE +EREMOTE :: Platform_Error.EREMOTE +EBADRPC :: Platform_Error.EBADRPC +ERPCMISMATCH :: Platform_Error.ERPCMISMATCH +EPROGUNAVAIL :: Platform_Error.EPROGUNAVAIL +EPROGMISMATCH :: Platform_Error.EPROGMISMATCH +EPROCUNAVAIL :: Platform_Error.EPROCUNAVAIL +ENOLCK :: Platform_Error.ENOLCK +ENOSYS :: Platform_Error.ENOSYS +EFTYPE :: Platform_Error.EFTYPE +EAUTH :: Platform_Error.EAUTH +ENEEDAUTH :: Platform_Error.ENEEDAUTH +EIPSEC :: Platform_Error.EIPSEC +ENOATTR :: Platform_Error.ENOATTR +EILSEQ :: Platform_Error.EILSEQ +ENOMEDIUM :: Platform_Error.ENOMEDIUM +EMEDIUMTYPE :: Platform_Error.EMEDIUMTYPE +EOVERFLOW :: Platform_Error.EOVERFLOW +ECANCELED :: Platform_Error.ECANCELED +EIDRM :: Platform_Error.EIDRM +ENOMSG :: Platform_Error.ENOMSG +ENOTSUP :: Platform_Error.ENOTSUP +EBADMSG :: Platform_Error.EBADMSG +ENOTRECOVERABLE :: Platform_Error.ENOTRECOVERABLE +EOWNERDEAD :: Platform_Error.EOWNERDEAD +EPROTO :: Platform_Error.EPROTO O_RDONLY :: 0x00000 O_WRONLY :: 0x00001 @@ -295,8 +392,8 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } -get_last_error :: proc "contextless" () -> int { - return int(__error()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__error()^) } fork :: proc() -> (Pid, Errno) { diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 7b7fb4686..36db0f622 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -4,11 +4,13 @@ import "core:sys/wasm/wasi" import "base:runtime" Handle :: distinct i32 -Errno :: distinct i32 +_Platform_Error :: enum i32 { + NONE = 0, +} INVALID_HANDLE :: -1 -ERROR_NONE :: Errno(wasi.errno_t.SUCCESS) +// ERROR_NONE :: Errno(wasi.errno_t.SUCCESS) // that is a weird error code. Probably better to remap it O_RDONLY :: 0x00000 O_WRONLY :: 0x00001 diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index ecfb0b419..0ec0b6091 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -7,7 +7,6 @@ import "base:intrinsics" Handle :: distinct uintptr File_Time :: distinct u64 -Errno :: distinct int INVALID_HANDLE :: ~Handle(0) @@ -27,38 +26,38 @@ O_SYNC :: 0x01000 O_ASYNC :: 0x02000 O_CLOEXEC :: 0x80000 +_Platform_Error :: win32.System_Error -ERROR_NONE: Errno : 0 -ERROR_FILE_NOT_FOUND: Errno : 2 -ERROR_PATH_NOT_FOUND: Errno : 3 -ERROR_ACCESS_DENIED: Errno : 5 -ERROR_INVALID_HANDLE: Errno : 6 -ERROR_NOT_ENOUGH_MEMORY: Errno : 8 -ERROR_NO_MORE_FILES: Errno : 18 -ERROR_HANDLE_EOF: Errno : 38 -ERROR_NETNAME_DELETED: Errno : 64 -ERROR_FILE_EXISTS: Errno : 80 -ERROR_INVALID_PARAMETER: Errno : 87 -ERROR_BROKEN_PIPE: Errno : 109 -ERROR_BUFFER_OVERFLOW: Errno : 111 -ERROR_INSUFFICIENT_BUFFER: Errno : 122 -ERROR_MOD_NOT_FOUND: Errno : 126 -ERROR_PROC_NOT_FOUND: Errno : 127 -ERROR_DIR_NOT_EMPTY: Errno : 145 -ERROR_ALREADY_EXISTS: Errno : 183 -ERROR_ENVVAR_NOT_FOUND: Errno : 203 -ERROR_MORE_DATA: Errno : 234 -ERROR_OPERATION_ABORTED: Errno : 995 -ERROR_IO_PENDING: Errno : 997 -ERROR_NOT_FOUND: Errno : 1168 -ERROR_PRIVILEGE_NOT_HELD: Errno : 1314 -WSAEACCES: Errno : 10013 -WSAECONNRESET: Errno : 10054 +ERROR_FILE_NOT_FOUND :: _Platform_Error(2) +ERROR_PATH_NOT_FOUND :: _Platform_Error(3) +ERROR_ACCESS_DENIED :: _Platform_Error(5) +ERROR_INVALID_HANDLE :: _Platform_Error(6) +ERROR_NOT_ENOUGH_MEMORY :: _Platform_Error(8) +ERROR_NO_MORE_FILES :: _Platform_Error(18) +ERROR_HANDLE_EOF :: _Platform_Error(38) +ERROR_NETNAME_DELETED :: _Platform_Error(64) +ERROR_FILE_EXISTS :: _Platform_Error(80) +ERROR_INVALID_PARAMETER :: _Platform_Error(87) +ERROR_BROKEN_PIPE :: _Platform_Error(109) +ERROR_BUFFER_OVERFLOW :: _Platform_Error(111) +ERROR_INSUFFICIENT_BUFFER :: _Platform_Error(122) +ERROR_MOD_NOT_FOUND :: _Platform_Error(126) +ERROR_PROC_NOT_FOUND :: _Platform_Error(127) +ERROR_DIR_NOT_EMPTY :: _Platform_Error(145) +ERROR_ALREADY_EXISTS :: _Platform_Error(183) +ERROR_ENVVAR_NOT_FOUND :: _Platform_Error(203) +ERROR_MORE_DATA :: _Platform_Error(234) +ERROR_OPERATION_ABORTED :: _Platform_Error(995) +ERROR_IO_PENDING :: _Platform_Error(997) +ERROR_NOT_FOUND :: _Platform_Error(1168) +ERROR_PRIVILEGE_NOT_HELD :: _Platform_Error(1314) +WSAEACCES :: _Platform_Error(10013) +WSAECONNRESET :: _Platform_Error(10054) // Windows reserves errors >= 1<<29 for application use -ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0 -ERROR_FILE_IS_NOT_DIR: Errno : 1<<29 + 1 -ERROR_NEGATIVE_OFFSET: Errno : 1<<29 + 2 +ERROR_FILE_IS_PIPE :: _Platform_Error(1<<29 + 0) +ERROR_FILE_IS_NOT_DIR :: _Platform_Error(1<<29 + 1) +ERROR_NEGATIVE_OFFSET :: _Platform_Error(1<<29 + 2) // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() diff --git a/core/prof/spall/spall_unix.odin b/core/prof/spall/spall_unix.odin index e6199d86b..e6ba7ecde 100644 --- a/core/prof/spall/spall_unix.odin +++ b/core/prof/spall/spall_unix.odin @@ -23,8 +23,8 @@ foreign libc { } @(no_instrumentation) -get_last_error :: proc "contextless" () -> int { - return int(__error()^) +get_last_error :: proc "contextless" () -> os.Platform_Error { + return os.Platform_Error(__error()^) } MAX_RW :: 0x7fffffff diff --git a/core/sync/futex_haiku.odin b/core/sync/futex_haiku.odin index b81743cad..6fe5894a0 100644 --- a/core/sync/futex_haiku.odin +++ b/core/sync/futex_haiku.odin @@ -2,7 +2,6 @@ package sync import "core:c" -import "base:runtime" import "core:sys/haiku" import "core:sys/unix" import "core:time" @@ -86,10 +85,10 @@ _futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> (ok: bool) { waiter.prev.next = waiter.next waiter.next.prev = waiter.prev - unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil) + _ = unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil) // FIXME: Add error handling! - return + return } _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration: time.Duration) -> (ok: bool) { @@ -133,10 +132,10 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration waiter.prev.next = waiter.next waiter.next.prev = waiter.prev - unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil) + unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil) - // FIXME: Add error handling! - return + // FIXME: Add error handling! + return } _futex_signal :: proc "contextless" (f: ^Futex) { diff --git a/core/sys/haiku/os.odin b/core/sys/haiku/os.odin index 1e00145eb..883072c2d 100644 --- a/core/sys/haiku/os.odin +++ b/core/sys/haiku/os.odin @@ -399,7 +399,7 @@ cpu_topology_node_info :: struct { }, _package: struct { vendor: cpu_vendor, - cache_line_size: u32 + cache_line_size: u32, }, _core: struct { model: u32, diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 01ff9da5b..78b88f21a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -127,6 +127,8 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y); +gb_internal bool is_exact_value_zero(ExactValue const &v); + enum LoadDirectiveResult { LoadDirective_Success = 0, LoadDirective_Error = 1, @@ -4364,6 +4366,25 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar } switch (t->kind) { + // IMPORTANT NOTE HACK(bill): This is just to allow for comparisons against `0` with the `os.Error` type + // as a kind of transition period + case Type_Enum: + if (operand->mode == Addressing_Constant && + target_type->kind == Type_Named && + target_type->Named.name == "Error") { + Entity *e = target_type->Named.type_name; + if (e->pkg && e->pkg->name == "os") { + if (is_exact_value_zero(operand->value)) { + check_is_expressible(c, operand, t); + if (operand->mode == Addressing_Invalid) { + return; + } + update_untyped_expr_value(c, operand->expr, operand->value); + } + } + } + break; + case Type_Basic: if (operand->mode == Addressing_Constant) { check_is_expressible(c, operand, t); From 9f9abb8fb30cb184771094b8cf44346147a6c2fc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:05:30 +0100 Subject: [PATCH 057/122] Use `union #shared_nil` for `os.Error` --- core/crypto/rand_windows.odin | 4 +-- core/os/dir_windows.odin | 4 +-- core/os/env_windows.odin | 4 +-- core/os/file_windows.odin | 39 ++++++++++++++-------------- core/os/os.odin | 17 +++++++++--- core/os/os_darwin.odin | 10 +++---- core/os/os_freebsd.odin | 2 +- core/os/os_haiku.odin | 2 +- core/os/os_linux.odin | 6 ++--- core/os/os_netbsd.odin | 2 +- core/os/os_openbsd.odin | 2 +- core/os/os_wasi.odin | 20 +++++++------- core/os/os_windows.odin | 10 ++++--- core/os/stat_windows.odin | 16 ++++++------ core/path/filepath/path_windows.odin | 4 +-- core/prof/spall/spall_windows.odin | 2 +- core/sys/wasm/wasi/wasi_api.odin | 1 + src/check_expr.cpp | 35 ++++++++++++------------- 18 files changed, 93 insertions(+), 87 deletions(-) diff --git a/core/crypto/rand_windows.odin b/core/crypto/rand_windows.odin index 6392cd51f..83a976e38 100644 --- a/core/crypto/rand_windows.odin +++ b/core/crypto/rand_windows.odin @@ -8,8 +8,8 @@ HAS_RAND_BYTES :: true @(private) _rand_bytes :: proc(dst: []byte) { - ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)) - if ret != os.ERROR_NONE { + ret := os.Platform_Error(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)) + if ret != nil { #partial switch ret { case os.ERROR_INVALID_HANDLE: // The handle to the first parameter is invalid. diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index 9ca78948e..adf502708 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -88,7 +88,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F find_data := &win32.WIN32_FIND_DATAW{} find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data) if find_handle == win32.INVALID_HANDLE_VALUE { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) return dfi[:], err } defer win32.FindClose(find_handle) @@ -101,7 +101,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F } if !win32.FindNextFileW(find_handle, find_data) { - e := Errno(win32.GetLastError()) + e := Platform_Error(win32.GetLastError()) if e == ERROR_NO_MORE_FILES { break } diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index 0e3c7f04a..7d26d5b4b 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -50,7 +50,7 @@ set_env :: proc(key, value: string) -> Errno { v := win32.utf8_to_wstring(value) if !win32.SetEnvironmentVariableW(k, v) { - return Errno(win32.GetLastError()) + return Platform_Error(win32.GetLastError()) } return 0 } @@ -59,7 +59,7 @@ set_env :: proc(key, value: string) -> Errno { unset_env :: proc(key: string) -> Errno { k := win32.utf8_to_wstring(key) if !win32.SetEnvironmentVariableW(k, nil) { - return Errno(win32.GetLastError()) + return Platform_Error(win32.GetLastError()) } return 0 } diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index d900c5e70..a00a49cba 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -55,20 +55,20 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn return handle, ERROR_NONE } - err := Errno(win32.GetLastError()) + err := Platform_Error(win32.GetLastError()) return INVALID_HANDLE, err } close :: proc(fd: Handle) -> Errno { if !win32.CloseHandle(win32.HANDLE(fd)) { - return Errno(win32.GetLastError()) + return Platform_Error(win32.GetLastError()) } return ERROR_NONE } flush :: proc(fd: Handle) -> (err: Errno) { if !win32.FlushFileBuffers(win32.HANDLE(fd)) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } @@ -90,7 +90,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil) if single_write_length <= 0 || !e { - err := Errno(win32.GetLastError()) + err := Platform_Error(win32.GetLastError()) return int(total_write), err } total_write += i64(single_write_length) @@ -118,7 +118,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { single_read_length: u32 ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil) if !ok { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length]) @@ -180,7 +180,7 @@ read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Errno) { return int(bytes_read), ERROR_NONE } } else { - return 0, Errno(win32.GetLastError()) + return 0, Platform_Error(win32.GetLastError()) } } return total_read, ERROR_NONE @@ -202,7 +202,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { dw_ptr := win32.SetFilePointer(win32.HANDLE(fd), lo, &hi, w) if dw_ptr == win32.INVALID_SET_FILE_POINTER { - err := Errno(win32.GetLastError()) + err := Platform_Error(win32.GetLastError()) return 0, err } return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE @@ -212,7 +212,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { length: win32.LARGE_INTEGER err: Errno if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return i64(length), err } @@ -220,7 +220,6 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { @(private) MAX_RW :: 1<<30 -ERROR_EOF :: 38 @(private) pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { @@ -241,7 +240,7 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { done: win32.DWORD e: Errno if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { - e = Errno(win32.GetLastError()) + e = Platform_Error(win32.GetLastError()) done = 0 } return int(done), e @@ -263,7 +262,7 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { done: win32.DWORD e: Errno if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) { - e = Errno(win32.GetLastError()) + e = Platform_Error(win32.GetLastError()) done = 0 } return int(done), e @@ -400,7 +399,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { win32.AcquireSRWLockExclusive(&cwd_lock) if !win32.SetCurrentDirectoryW(wstr) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } win32.ReleaseSRWLockExclusive(&cwd_lock) @@ -415,7 +414,7 @@ make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) { wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.CreateDirectoryW(wpath, nil) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } @@ -426,7 +425,7 @@ remove_directory :: proc(path: string) -> (err: Errno) { wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.RemoveDirectoryW(wpath) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } @@ -498,7 +497,7 @@ link :: proc(old_name, new_name: string) -> (err: Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() n := win32.utf8_to_wstring(fix_long_path(new_name)) o := win32.utf8_to_wstring(fix_long_path(old_name)) - return Errno(win32.CreateHardLinkW(n, o, nil)) + return Platform_Error(win32.CreateHardLinkW(n, o, nil)) } unlink :: proc(path: string) -> (err: Errno) { @@ -506,7 +505,7 @@ unlink :: proc(path: string) -> (err: Errno) { wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.DeleteFileW(wpath) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } @@ -519,7 +518,7 @@ rename :: proc(old_path, new_path: string) -> (err: Errno) { to := win32.utf8_to_wstring(new_path, context.temp_allocator) if !win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } @@ -537,7 +536,7 @@ ftruncate :: proc(fd: Handle, length: i64) -> (err: Errno) { } ok := win32.SetEndOfFile(win32.HANDLE(fd)) if !ok { - return Errno(win32.GetLastError()) + return Platform_Error(win32.GetLastError()) } return ERROR_NONE } @@ -588,7 +587,7 @@ remove :: proc(name: string) -> Errno { } } - return Errno(err) + return Platform_Error(err) } @@ -597,7 +596,7 @@ pipe :: proc() -> (r, w: Handle, err: Errno) { sa.nLength = size_of(win32.SECURITY_ATTRIBUTES) sa.bInheritHandle = true if !win32.CreatePipe((^win32.HANDLE)(&r), (^win32.HANDLE)(&w), &sa, 0) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } diff --git a/core/os/os.odin b/core/os/os.odin index 3f48c59df..6f2cdb8e3 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -1,5 +1,6 @@ package os +import "base:intrinsics" import "base:runtime" import "core:strconv" import "core:unicode/utf8" @@ -14,10 +15,18 @@ SEEK_CUR :: 1 SEEK_END :: 2 Platform_Error :: _Platform_Error -Error :: Platform_Error -Errno :: Error // alias +#assert(size_of(Platform_Error) <= 4) +#assert(intrinsics.type_has_nil(Platform_Error)) -ERROR_NONE :: Errno(0) +Errno :: Error // alias for legacy use + +Error :: union #shared_nil { + Platform_Error, + runtime.Allocator_Error, +} +#assert(size_of(Error) <= 8) + +ERROR_NONE :: Error{} write_string :: proc(fd: Handle, str: string) -> (int, Errno) { return write(fd, transmute([]byte)str) @@ -67,7 +76,7 @@ write_encoded_rune :: proc(fd: Handle, r: rune) { read_at_least :: proc(fd: Handle, buf: []byte, min: int) -> (n: int, err: Errno) { if len(buf) < min { - return 0, -1 + return 0, Platform_Error(~intrinsics.type_core_type(Platform_Error)(0)) // TODO(bill): replace this error } nn := max(int) for nn > 0 && n < min && err == 0 { diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index f72529682..216620aa7 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -636,7 +636,7 @@ foreign dl { } get_last_error :: proc "contextless" () -> Error { - return Error(__error()^) + return Platform_Error(__error()^) } get_last_error_string :: proc() -> string { @@ -678,11 +678,11 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno } fchmod :: proc(fd: Handle, mode: u16) -> Errno { - return cast(Errno)_unix_fchmod(fd, mode) + return cast(Platform_Error)_unix_fchmod(fd, mode) } close :: proc(fd: Handle) -> Errno { - return cast(Errno)_unix_close(fd) + return cast(Platform_Error)_unix_close(fd) } // If you read or write more than `SSIZE_MAX` bytes, most darwin implementations will return `EINVAL` @@ -756,7 +756,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { final_offset := i64(_unix_lseek(fd, int(offset), c.int(whence))) if final_offset == -1 { - return 0, 1 + return 0, Platform_Error.EPERM } return final_offset, 0 } @@ -1011,7 +1011,7 @@ access :: proc(path: string, mask: int) -> bool { } flush :: proc(fd: Handle) -> Errno { - return cast(Errno)_unix_fsync(fd) + return cast(Platform_Error)_unix_fsync(fd) } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 7090a7773..d9efe0902 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -420,7 +420,7 @@ is_path_separator :: proc(r: rune) -> bool { } get_last_error :: proc "contextless" () -> Error { - return Error(__errno_location()^) + return Platform_Error(__errno_location()^) } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index 03e2c5e64..784ae1135 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -182,7 +182,7 @@ is_path_separator :: proc(r: rune) -> bool { } get_last_error :: proc "contextless" () -> Error { - return Error(__error()^) + return Platform_Error(__error()^) } fork :: proc() -> (Pid, Errno) { diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index ace24d26a..bd55a229b 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -514,14 +514,14 @@ is_path_separator :: proc(r: rune) -> bool { @private _get_errno :: proc(res: int) -> Errno { if res < 0 && res > -4096 { - return Errno(-res) + return Platform_Error(-res) } - return 0 + return nil } // get errno from libc get_last_error :: proc "contextless" () -> Error { - return Error(__errno_location()^) + return Platform_Error(__errno_location()^) } personality :: proc(persona: u64) -> (Errno) { diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index b27daac3a..3de440542 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -478,7 +478,7 @@ is_path_separator :: proc(r: rune) -> bool { } get_last_error :: proc "contextless" () -> Error { - return Error(__errno_location()^) + return Platform_Error(__errno_location()^) } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index cc7642387..f1ad9ab38 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -393,7 +393,7 @@ is_path_separator :: proc(r: rune) -> bool { } get_last_error :: proc "contextless" () -> Error { - return Error(__error()^) + return Platform_Error(__error()^) } fork :: proc() -> (Pid, Errno) { diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 36db0f622..f2c5b62b4 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -4,9 +4,7 @@ import "core:sys/wasm/wasi" import "base:runtime" Handle :: distinct i32 -_Platform_Error :: enum i32 { - NONE = 0, -} +_Platform_Error :: wasi.errno_t INVALID_HANDLE :: -1 @@ -150,22 +148,22 @@ wasi_match_preopen :: proc(path: string) -> (wasi.fd_t, string, bool) { write :: proc(fd: Handle, data: []byte) -> (int, Errno) { iovs := wasi.ciovec_t(data) n, err := wasi.fd_write(wasi.fd_t(fd), {iovs}) - return int(n), Errno(err) + return int(n), Platform_Error(err) } read :: proc(fd: Handle, data: []byte) -> (int, Errno) { iovs := wasi.iovec_t(data) n, err := wasi.fd_read(wasi.fd_t(fd), {iovs}) - return int(n), Errno(err) + return int(n), Platform_Error(err) } write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { iovs := wasi.ciovec_t(data) n, err := wasi.fd_pwrite(wasi.fd_t(fd), {iovs}, wasi.filesize_t(offset)) - return int(n), Errno(err) + return int(n), Platform_Error(err) } read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { iovs := wasi.iovec_t(data) n, err := wasi.fd_pread(wasi.fd_t(fd), {iovs}, wasi.filesize_t(offset)) - return int(n), Errno(err) + return int(n), Platform_Error(err) } open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) { oflags: wasi.oflags_t @@ -203,15 +201,15 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn } fd, err := wasi.path_open(dir_fd, {.SYMLINK_FOLLOW}, relative, oflags, rights, {}, fdflags) - return Handle(fd), Errno(err) + return Handle(fd), Platform_Error(err) } close :: proc(fd: Handle) -> Errno { err := wasi.fd_close(wasi.fd_t(fd)) - return Errno(err) + return Platform_Error(err) } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { n, err := wasi.fd_seek(wasi.fd_t(fd), wasi.filedelta_t(offset), wasi.whence_t(whence)) - return i64(n), Errno(err) + return i64(n), Platform_Error(err) } current_thread_id :: proc "contextless" () -> int { return 0 @@ -224,7 +222,7 @@ _processor_core_count :: proc() -> int { file_size :: proc(fd: Handle) -> (i64, Errno) { stat, err := wasi.fd_filestat_get(wasi.fd_t(fd)) if err != nil { - return 0, Errno(err) + return 0, Platform_Error(err) } return i64(stat.size), 0 } diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 0ec0b6091..52f7062a0 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -35,6 +35,7 @@ ERROR_INVALID_HANDLE :: _Platform_Error(6) ERROR_NOT_ENOUGH_MEMORY :: _Platform_Error(8) ERROR_NO_MORE_FILES :: _Platform_Error(18) ERROR_HANDLE_EOF :: _Platform_Error(38) +ERROR_EOF :: ERROR_HANDLE_EOF ERROR_NETNAME_DELETED :: _Platform_Error(64) ERROR_FILE_EXISTS :: _Platform_Error(80) ERROR_INVALID_PARAMETER :: _Platform_Error(87) @@ -62,14 +63,15 @@ ERROR_NEGATIVE_OFFSET :: _Platform_Error(1<<29 + 2) // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() - - +get_last_error :: proc "contextless" () -> Error { + return Platform_Error(win32.GetLastError()) +} last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { file_info: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(win32.HANDLE(fd), &file_info) { - return 0, Errno(win32.GetLastError()) + return 0, Platform_Error(win32.GetLastError()) } lo := File_Time(file_info.ftLastWriteTime.dwLowDateTime) hi := File_Time(file_info.ftLastWriteTime.dwHighDateTime) @@ -81,7 +83,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { wide_path := win32.utf8_to_wstring(name) if !win32.GetFileAttributesExW(wide_path, win32.GetFileExInfoStandard, &data) { - return 0, Errno(win32.GetLastError()) + return 0, Platform_Error(win32.GetLastError()) } l := File_Time(data.ftLastWriteTime.dwLowDateTime) diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index 4bb3bd4c4..d584749cc 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -19,7 +19,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa for { n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) if n == 0 { - return "", Errno(win32.GetLastError()) + return "", Platform_Error(win32.GetLastError()) } if n <= u32(len(buf)) { return win32.utf16_to_utf8(buf[:n], allocator) or_else "", ERROR_NONE @@ -54,7 +54,7 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al fd: win32.WIN32_FIND_DATAW sh := win32.FindFirstFileW(wname, &fd) if sh == win32.INVALID_HANDLE_VALUE { - e = Errno(win32.GetLastError()) + e = Platform_Error(win32.GetLastError()) return } win32.FindClose(sh) @@ -64,7 +64,7 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil) if h == win32.INVALID_HANDLE_VALUE { - e = Errno(win32.GetLastError()) + e = Platform_Error(win32.GetLastError()) return } defer win32.CloseHandle(h) @@ -151,7 +151,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ( n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0) if n == 0 { - return nil, Errno(win32.GetLastError()) + return nil, Platform_Error(win32.GetLastError()) } buf := make([]u16, max(n, win32.DWORD(260))+1, allocator) buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0) @@ -273,16 +273,16 @@ file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Errno) { d: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(h, &d) { - err := Errno(win32.GetLastError()) + err := Platform_Error(win32.GetLastError()) return {}, err } ti: win32.FILE_ATTRIBUTE_TAG_INFO if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) { - err := win32.GetLastError() - if err != u32(ERROR_INVALID_PARAMETER) { - return {}, Errno(err) + err := Platform_Error(win32.GetLastError()) + if err != ERROR_INVALID_PARAMETER { + return {}, err } // Indicate this is a symlink on FAT file systems ti.ReparseTag = 0 diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin index 5ebd2cdc2..ae26e1394 100644 --- a/core/path/filepath/path_windows.odin +++ b/core/path/filepath/path_windows.odin @@ -63,14 +63,14 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Errno) { p := win32.utf8_to_utf16(name, ta) n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil) if n == 0 { - return "", os.Errno(win32.GetLastError()) + return "", os.Platform_Error(win32.GetLastError()) } buf := make([]u16, n, ta) n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) if n == 0 { delete(buf) - return "", os.Errno(win32.GetLastError()) + return "", os.Platform_Error(win32.GetLastError()) } return win32.utf16_to_utf8(buf[:n], ta) or_else "", os.ERROR_NONE diff --git a/core/prof/spall/spall_windows.odin b/core/prof/spall/spall_windows.odin index 4d96c111a..a55c42852 100644 --- a/core/prof/spall/spall_windows.odin +++ b/core/prof/spall/spall_windows.odin @@ -25,7 +25,7 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (int, os.Errno) #n e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil) if single_write_length <= 0 || !e { - err := os.Errno(win32.GetLastError()) + err := os.Platform_Error(win32.GetLastError()) return int(total_write), err } total_write += i64(single_write_length) diff --git a/core/sys/wasm/wasi/wasi_api.odin b/core/sys/wasm/wasi/wasi_api.odin index 22abd8dc4..6ae6c9151 100644 --- a/core/sys/wasm/wasi/wasi_api.odin +++ b/core/sys/wasm/wasi/wasi_api.odin @@ -16,6 +16,7 @@ CLOCK_REALTIME :: clockid_t(2) CLOCK_THREAD_CPUTIME_ID :: clockid_t(3) errno_t :: enum u16 { + NONE = 0, // No error occurred. System call completed successfully. SUCCESS = 0, // Argument list too long. diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 78b88f21a..9df3c7076 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4366,25 +4366,6 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar } switch (t->kind) { - // IMPORTANT NOTE HACK(bill): This is just to allow for comparisons against `0` with the `os.Error` type - // as a kind of transition period - case Type_Enum: - if (operand->mode == Addressing_Constant && - target_type->kind == Type_Named && - target_type->Named.name == "Error") { - Entity *e = target_type->Named.type_name; - if (e->pkg && e->pkg->name == "os") { - if (is_exact_value_zero(operand->value)) { - check_is_expressible(c, operand, t); - if (operand->mode == Addressing_Invalid) { - return; - } - update_untyped_expr_value(c, operand->expr, operand->value); - } - } - } - break; - case Type_Basic: if (operand->mode == Addressing_Constant) { check_is_expressible(c, operand, t); @@ -4478,6 +4459,22 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar case Type_Union: + // IMPORTANT NOTE HACK(bill): This is just to allow for comparisons against `0` with the `os.Error` type + // as a kind of transition period + if (operand->mode == Addressing_Constant && + target_type->kind == Type_Named && + target_type->Named.name == "Error") { + Entity *e = target_type->Named.type_name; + if (e->pkg && e->pkg->name == "os") { + if (is_exact_value_zero(operand->value) && + (operand->value.kind == ExactValue_Integer || + operand->value.kind == ExactValue_Float)) { + update_untyped_expr_value(c, operand->expr, empty_exact_value); + break; + } + } + } + // "fallthrough" if (!is_operand_nil(*operand) && !is_operand_uninit(*operand)) { TEMPORARY_ALLOCATOR_GUARD(); From 1826b0c700f4a4ae524c249bf761a6d274a0dd6e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:10:17 +0100 Subject: [PATCH 058/122] Fix copy-replace errors --- core/os/os2/errors.odin | 8 ++++---- core/os/os2/errors_linux.odin | 2 +- core/os/os2/errors_windows.odin | 2 +- core/os/os2/file_stream.odin | 2 +- core/os/os2/process_windows.odin | 14 +++++++------- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/core/os/os2/errors.odin b/core/os/os2/errors.odin index e5a0bb722..2b9b3528e 100644 --- a/core/os/os2/errors.odin +++ b/core/os/os2/errors.odin @@ -3,7 +3,7 @@ package os2 import "core:io" import "base:runtime" -General_Platform_Error :: enum u32 { +General_Error :: enum u32 { None, Permission_Denied, @@ -29,7 +29,7 @@ General_Platform_Error :: enum u32 { Unsupported, } -Platform_Platform_Error :: enum i32 {None=0} +Platform_Error :: enum i32 {None=0} Error :: union #shared_nil { General_Error, @@ -43,7 +43,7 @@ ERROR_NONE :: Error{} -is_platform_Platform_Error :: proc(ferr: Error) -> (err: i32, ok: bool) { +is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { v := ferr.(Platform_Error) or_else {} return i32(v), i32(v) != 0 } @@ -104,7 +104,7 @@ error_string :: proc(ferr: Error) -> string { return "unknown error" } -print_Platform_Error :: proc(f: ^File, ferr: Error, msg: string) { +print_error :: proc(f: ^File, ferr: Error, msg: string) { TEMP_ALLOCATOR_GUARD() err_str := error_string(ferr) diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin index 0da9e1452..d7234ce8b 100644 --- a/core/os/os2/errors_linux.odin +++ b/core/os/os2/errors_linux.odin @@ -142,7 +142,7 @@ _errno_strings : [linux.Errno]string = { } -_get_platform_Platform_Error :: proc(errno: linux.Errno) -> Error { +_get_platform_error :: proc(errno: linux.Errno) -> Error { #partial switch errno { case .NONE: return nil diff --git a/core/os/os2/errors_windows.odin b/core/os/os2/errors_windows.odin index 00dacd491..6421d26ee 100644 --- a/core/os/os2/errors_windows.odin +++ b/core/os/os2/errors_windows.odin @@ -20,7 +20,7 @@ _error_string :: proc(errno: i32) -> string { return "" } -_get_platform_Platform_Error :: proc() -> Error { +_get_platform_error :: proc() -> Error { err := win32.GetLastError() if err == 0 { return nil diff --git a/core/os/os2/file_stream.odin b/core/os/os2/file_stream.odin index 89bd59809..84176928d 100644 --- a/core/os/os2/file_stream.odin +++ b/core/os/os2/file_stream.odin @@ -15,7 +15,7 @@ to_reader :: to_stream @(private) -error_to_io_Platform_Error :: proc(ferr: Error) -> io.Error { +error_to_io_error :: proc(ferr: Error) -> io.Error { if ferr == nil { return .None } diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin index 57f162eab..47fd62401 100644 --- a/core/os/os2/process_windows.odin +++ b/core/os/os2/process_windows.odin @@ -101,7 +101,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator if selection >= {.PPid, .Priority} { entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = GeneralPlatform_Error.Not_Exist + err = General_Error.Not_Exist return } if .PPid in selection { @@ -147,7 +147,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator } if process_info.PebBaseAddress == nil { // Not sure what the error is - err = GeneralPlatform_Error.Unsupported + err = General_Error.Unsupported return } process_peb: win32.PEB @@ -210,7 +210,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields if selection >= {.PPid, .Priority} { // snap process entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = GeneralPlatform_Error.Not_Exist + err = General_Error.Not_Exist return } if .PPid in selection { @@ -239,7 +239,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields } if process_info.PebBaseAddress == nil { // Not sure what the error is - err = GeneralPlatform_Error.Unsupported + err = General_Error.Unsupported return } @@ -301,7 +301,7 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime if selection >= {.PPid, .Priority} { // snap process entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = GeneralPlatform_Error.Not_Exist + err = General_Error.Not_Exist return } if .PPid in selection { @@ -459,7 +459,7 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (process_stat } return case win32.WAIT_TIMEOUT: - err = GeneralPlatform_Error.Timeout + err = General_Error.Timeout return case: err = _get_platform_error() @@ -508,7 +508,7 @@ _process_entry_by_pid :: proc(pid: int) -> (entry: win32.PROCESSENTRY32W, err: E } status = win32.Process32NextW(snap, &entry) } - err = GeneralPlatform_Error.Not_Exist + err = General_Error.Not_Exist return } From 7dae38ce895e9e8b92b5fae5ac3afb3dcc57c692 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:12:45 +0100 Subject: [PATCH 059/122] Begin mocking out for other errors --- core/os/os.odin | 50 +++++++++++++++++++++++--------------- core/os/os2/file_util.odin | 15 ++++++++++++ 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/core/os/os.odin b/core/os/os.odin index 6f2cdb8e3..b012cbbb1 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -2,6 +2,7 @@ package os import "base:intrinsics" import "base:runtime" +import "core:io" import "core:strconv" import "core:unicode/utf8" @@ -21,8 +22,9 @@ Platform_Error :: _Platform_Error Errno :: Error // alias for legacy use Error :: union #shared_nil { - Platform_Error, + io.Error, runtime.Allocator_Error, + Platform_Error, } #assert(size_of(Error) <= 8) @@ -45,38 +47,48 @@ write_rune :: proc(fd: Handle, r: rune) -> (int, Errno) { return write(fd, b[:n]) } -write_encoded_rune :: proc(fd: Handle, r: rune) { - write_byte(fd, '\'') +write_encoded_rune :: proc(f: Handle, r: rune) -> (n: int, err: Error) { + wrap :: proc(m: int, merr: Error, n: ^int, err: ^Error) -> bool { + n^ += m + if merr != nil { + err^ = merr + return true + } + return false + } + + if wrap(write_byte(f, '\''), &n, &err) { return } switch r { - case '\a': write_string(fd, "\\a") - case '\b': write_string(fd, "\\b") - case '\e': write_string(fd, "\\e") - case '\f': write_string(fd, "\\f") - case '\n': write_string(fd, "\\n") - case '\r': write_string(fd, "\\r") - case '\t': write_string(fd, "\\t") - case '\v': write_string(fd, "\\v") + case '\a': if wrap(write_string(f, "\\a"), &n, &err) { return } + case '\b': if wrap(write_string(f, "\\b"), &n, &err) { return } + case '\e': if wrap(write_string(f, "\\e"), &n, &err) { return } + case '\f': if wrap(write_string(f, "\\f"), &n, &err) { return } + case '\n': if wrap(write_string(f, "\\n"), &n, &err) { return } + case '\r': if wrap(write_string(f, "\\r"), &n, &err) { return } + case '\t': if wrap(write_string(f, "\\t"), &n, &err) { return } + case '\v': if wrap(write_string(f, "\\v"), &n, &err) { return } case: if r < 32 { - write_string(fd, "\\x") + if wrap(write_string(f, "\\x"), &n, &err) { return } b: [2]byte s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) switch len(s) { - case 0: write_string(fd, "00") - case 1: write_rune(fd, '0') - case 2: write_string(fd, s) + case 0: if wrap(write_string(f, "00"), &n, &err) { return } + case 1: if wrap(write_rune(f, '0'), &n, &err) { return } + case 2: if wrap(write_string(f, s), &n, &err) { return } } } else { - write_rune(fd, r) + if wrap(write_rune(f, r), &n, &err) { return } } } - write_byte(fd, '\'') + _ = wrap(write_byte(f, '\''), &n, &err) + return } read_at_least :: proc(fd: Handle, buf: []byte, min: int) -> (n: int, err: Errno) { if len(buf) < min { - return 0, Platform_Error(~intrinsics.type_core_type(Platform_Error)(0)) // TODO(bill): replace this error + return 0, io.Error.Short_Buffer } nn := max(int) for nn > 0 && n < min && err == 0 { @@ -84,7 +96,7 @@ read_at_least :: proc(fd: Handle, buf: []byte, min: int) -> (n: int, err: Errno) n += nn } if n >= min { - err = 0 + err = nil } return } diff --git a/core/os/os2/file_util.odin b/core/os/os2/file_util.odin index 2011d1cc4..c2cd512b2 100644 --- a/core/os/os2/file_util.odin +++ b/core/os/os2/file_util.odin @@ -73,6 +73,21 @@ write_encoded_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) { return } +read_at_least :: proc(f: ^File, buf: []byte, min: int) -> (n: int, err: Error) { + if len(buf) < min { + return 0, .Short_Buffer + } + nn := max(int) + for nn > 0 && n < min && err == nil { + nn, err = read(f, buf[n:]) + n += nn + } + if n >= min { + err = nil + } + return +} + write_ptr :: proc(f: ^File, data: rawptr, len: int) -> (n: int, err: Error) { return write(f, ([^]byte)(data)[:len]) From 29b6eebcd5641c6457dee874164af8432d169c84 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:21:09 +0100 Subject: [PATCH 060/122] Clean up error handling --- core/os/dir_windows.odin | 4 +-- core/os/env_windows.odin | 22 +++++------- core/os/file_windows.odin | 73 ++++++++++++++++---------------------- core/os/os.odin | 14 ++++---- core/os/os2/file_util.odin | 3 ++ core/os/os_darwin.odin | 30 ++++++++-------- core/os/os_freebsd.odin | 14 ++++---- core/os/os_haiku.odin | 4 +-- core/os/os_linux.odin | 20 +++++------ core/os/os_netbsd.odin | 14 ++++---- core/os/os_openbsd.odin | 14 ++++---- core/os/os_wasi.odin | 2 +- core/os/os_windows.odin | 8 ++--- core/os/stat_windows.odin | 21 +++++------ core/os/stream.odin | 10 +++--- 15 files changed, 118 insertions(+), 135 deletions(-) diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index adf502708..2d55db66f 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -88,7 +88,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F find_data := &win32.WIN32_FIND_DATAW{} find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data) if find_handle == win32.INVALID_HANDLE_VALUE { - err = Platform_Error(win32.GetLastError()) + err = get_last_error() return dfi[:], err } defer win32.FindClose(find_handle) @@ -101,7 +101,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F } if !win32.FindNextFileW(find_handle, find_data) { - e := Platform_Error(win32.GetLastError()) + e := get_last_error() if e == ERROR_NO_MORE_FILES { break } diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index 7d26d5b4b..894a85bd9 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -13,21 +13,15 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin } wkey := win32.utf8_to_wstring(key) n := win32.GetEnvironmentVariableW(wkey, nil, 0) - if n == 0 { - err := win32.GetLastError() - if err == u32(ERROR_ENVVAR_NOT_FOUND) { - return "", false - } + if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND { + return "", false } runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) b := make([dynamic]u16, n, context.temp_allocator) n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b))) - if n == 0 { - err := win32.GetLastError() - if err == u32(ERROR_ENVVAR_NOT_FOUND) { - return "", false - } + if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND { + return "", false } value, _ = win32.utf16_to_utf8(b[:n], allocator) found = true @@ -50,18 +44,18 @@ set_env :: proc(key, value: string) -> Errno { v := win32.utf8_to_wstring(value) if !win32.SetEnvironmentVariableW(k, v) { - return Platform_Error(win32.GetLastError()) + return get_last_error() } - return 0 + return nil } // unset_env unsets a single environment variable unset_env :: proc(key: string) -> Errno { k := win32.utf8_to_wstring(key) if !win32.SetEnvironmentVariableW(k, nil) { - return Platform_Error(win32.GetLastError()) + return get_last_error() } - return 0 + return nil } // environ returns a copy of strings representing the environment, in the form "key=value" diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index a00a49cba..ab780982d 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -55,20 +55,20 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn return handle, ERROR_NONE } - err := Platform_Error(win32.GetLastError()) + err := get_last_error() return INVALID_HANDLE, err } close :: proc(fd: Handle) -> Errno { if !win32.CloseHandle(win32.HANDLE(fd)) { - return Platform_Error(win32.GetLastError()) + return get_last_error() } - return ERROR_NONE + return nil } flush :: proc(fd: Handle) -> (err: Errno) { if !win32.FlushFileBuffers(win32.HANDLE(fd)) { - err = Platform_Error(win32.GetLastError()) + err = get_last_error() } return } @@ -90,8 +90,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil) if single_write_length <= 0 || !e { - err := Platform_Error(win32.GetLastError()) - return int(total_write), err + return int(total_write), get_last_error() } total_write += i64(single_write_length) } @@ -101,14 +100,14 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { @(private="file") read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { if len(b) == 0 { - return 0, 0 + return 0, nil } BUF_SIZE :: 386 buf16: [BUF_SIZE]u16 buf8: [4*BUF_SIZE]u8 - for n < len(b) && err == 0 { + for n < len(b) && err == nil { min_read := max(len(b)/4, 1 if len(b) > 0 else 0) max_read := u32(min(BUF_SIZE, min_read)) if max_read == 0 { @@ -118,7 +117,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { single_read_length: u32 ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil) if !ok { - err = Platform_Error(win32.GetLastError()) + err = get_last_error() } buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length]) @@ -165,7 +164,7 @@ read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Errno) { if is_console { total_read, err = read_console(handle, data[total_read:][:to_read]) - if err != 0 { + if err != nil { return total_read, err } } else { @@ -180,10 +179,10 @@ read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Errno) { return int(bytes_read), ERROR_NONE } } else { - return 0, Platform_Error(win32.GetLastError()) + return 0, get_last_error() } } - return total_read, ERROR_NONE + return total_read, nil } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { @@ -202,7 +201,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { dw_ptr := win32.SetFilePointer(win32.HANDLE(fd), lo, &hi, w) if dw_ptr == win32.INVALID_SET_FILE_POINTER { - err := Platform_Error(win32.GetLastError()) + err := get_last_error() return 0, err } return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE @@ -212,7 +211,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { length: win32.LARGE_INTEGER err: Errno if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) { - err = Platform_Error(win32.GetLastError()) + err = get_last_error() } return i64(length), err } @@ -240,7 +239,7 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { done: win32.DWORD e: Errno if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { - e = Platform_Error(win32.GetLastError()) + e = get_last_error() done = 0 } return int(done), e @@ -262,7 +261,7 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { done: win32.DWORD e: Errno if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) { - e = Platform_Error(win32.GetLastError()) + e = get_last_error() done = 0 } return int(done), e @@ -287,10 +286,10 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { for len(b) > 0 { m, e := pread(fd, b, offset) if e == ERROR_EOF { - err = 0 + err = nil break } - if e != 0 { + if e != nil { err = e break } @@ -317,11 +316,7 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) b, offset := data, offset for len(b) > 0 { - m, e := pwrite(fd, b, offset) - if e != 0 { - err = e - break - } + m := pwrite(fd, b, offset) or_return n += m b = b[m:] offset += i64(m) @@ -399,7 +394,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { win32.AcquireSRWLockExclusive(&cwd_lock) if !win32.SetCurrentDirectoryW(wstr) { - err = Platform_Error(win32.GetLastError()) + err = get_last_error() } win32.ReleaseSRWLockExclusive(&cwd_lock) @@ -414,7 +409,7 @@ make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) { wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.CreateDirectoryW(wpath, nil) { - err = Platform_Error(win32.GetLastError()) + err = get_last_error() } return } @@ -425,7 +420,7 @@ remove_directory :: proc(path: string) -> (err: Errno) { wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.RemoveDirectoryW(wpath) { - err = Platform_Error(win32.GetLastError()) + err = get_last_error() } return } @@ -505,7 +500,7 @@ unlink :: proc(path: string) -> (err: Errno) { wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.DeleteFileW(wpath) { - err = Platform_Error(win32.GetLastError()) + err = get_last_error() } return } @@ -518,33 +513,27 @@ rename :: proc(old_path, new_path: string) -> (err: Errno) { to := win32.utf8_to_wstring(new_path, context.temp_allocator) if !win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) { - err = Platform_Error(win32.GetLastError()) + err = get_last_error() } return } ftruncate :: proc(fd: Handle, length: i64) -> (err: Errno) { - curr_off, e := seek(fd, 0, 1) - if e != 0 { - return e - } + curr_off := seek(fd, 0, 1) or_return defer seek(fd, curr_off, 0) - _, e = seek(fd, length, 0) - if e != 0 { - return e - } + _= seek(fd, length, 0) or_return ok := win32.SetEndOfFile(win32.HANDLE(fd)) if !ok { - return Platform_Error(win32.GetLastError()) + return get_last_error() } - return ERROR_NONE + return nil } truncate :: proc(path: string, length: i64) -> (err: Errno) { fd: Handle fd, err = open(path, O_WRONLY|O_CREATE, 0o666) - if err != 0 { + if err != nil { return } defer close(fd) @@ -560,13 +549,13 @@ remove :: proc(name: string) -> Errno { err = win32.GetLastError() } if err == 0 { - return 0 + return nil } if !win32.RemoveDirectoryW(p) { err1 = win32.GetLastError() } if err1 == 0 { - return 0 + return nil } if err != err1 { @@ -596,7 +585,7 @@ pipe :: proc() -> (r, w: Handle, err: Errno) { sa.nLength = size_of(win32.SECURITY_ATTRIBUTES) sa.bInheritHandle = true if !win32.CreatePipe((^win32.HANDLE)(&r), (^win32.HANDLE)(&w), &sa, 0) { - err = Platform_Error(win32.GetLastError()) + err = get_last_error() } return } diff --git a/core/os/os.odin b/core/os/os.odin index b012cbbb1..7bdef0e6f 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -91,7 +91,7 @@ read_at_least :: proc(fd: Handle, buf: []byte, min: int) -> (n: int, err: Errno) return 0, io.Error.Short_Buffer } nn := max(int) - for nn > 0 && n < min && err == 0 { + for nn > 0 && n < min && err == nil { nn, err = read(fd, buf[n:]) n += nn } @@ -108,13 +108,13 @@ read_full :: proc(fd: Handle, buf: []byte) -> (n: int, err: Errno) { file_size_from_path :: proc(path: string) -> i64 { fd, err := open(path, O_RDONLY, 0) - if err != 0 { + if err != nil { return -1 } defer close(fd) length: i64 - if length, err = file_size(fd); err != 0 { + if length, err = file_size(fd); err != nil { return -1 } return length @@ -124,7 +124,7 @@ read_entire_file_from_filename :: proc(name: string, allocator := context.alloca context.allocator = allocator fd, err := open(name, O_RDONLY, 0) - if err != 0 { + if err != nil { return nil, false } defer close(fd) @@ -137,7 +137,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator, length: i64 err: Errno - if length, err = file_size(fd); err != 0 { + if length, err = file_size(fd); err != nil { return nil, false } @@ -176,13 +176,13 @@ write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (succ } fd, err := open(name, flags, mode) - if err != 0 { + if err != nil { return false } defer close(fd) _, write_err := write(fd, data) - return write_err == 0 + return write_err == nil } write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) { diff --git a/core/os/os2/file_util.odin b/core/os/os2/file_util.odin index c2cd512b2..f79afdb73 100644 --- a/core/os/os2/file_util.odin +++ b/core/os/os2/file_util.odin @@ -88,6 +88,9 @@ read_at_least :: proc(f: ^File, buf: []byte, min: int) -> (n: int, err: Error) { return } +read_full :: proc(f: ^File, buf: []byte) -> (n: int, err: Error) { + return read_at_least(f, buf, len(buf)) +} write_ptr :: proc(f: ^File, data: rawptr, len: int) -> (n: int, err: Error) { return write(f, ([^]byte)(data)[:len]) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 216620aa7..33151953d 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -668,13 +668,13 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno */ if mode != 0 && !isDir { err := fchmod(handle, cast(u16)mode) - if err != 0 { + if err != nil { _unix_close(handle) return INVALID_HANDLE, err } } - return handle, 0 + return handle, nil } fchmod :: proc(fd: Handle, mode: u16) -> Errno { @@ -758,7 +758,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { if final_offset == -1 { return 0, Platform_Error.EPERM } - return final_offset, 0 + return final_offset, nil } file_size :: proc(fd: Handle) -> (i64, Errno) { @@ -867,7 +867,7 @@ remove :: proc(path: string) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } @private @@ -921,7 +921,7 @@ _closedir :: proc(dirp: Dir) -> Errno { if rc != 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } @private @@ -1037,7 +1037,7 @@ set_env :: proc(key, value: string) -> Errno { if res < 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } unset_env :: proc(key: string) -> Errno { @@ -1047,7 +1047,7 @@ unset_env :: proc(key: string) -> Errno { if res < 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } get_current_directory :: proc() -> string { @@ -1074,7 +1074,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } make_directory :: proc(path: string, mode: u16 = 0o775) -> Errno { @@ -1084,7 +1084,7 @@ make_directory :: proc(path: string, mode: u16 = 0o775) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } exit :: proc "contextless" (code: int) -> ! { @@ -1169,7 +1169,7 @@ connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { if result < 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { @@ -1177,7 +1177,7 @@ bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { if result < 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Errno) { @@ -1193,7 +1193,7 @@ listen :: proc(sd: Socket, backlog: int) -> (Errno) { if result < 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> (Errno) { @@ -1201,7 +1201,7 @@ setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: if result < 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Errno { @@ -1209,7 +1209,7 @@ getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: if result < 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Errno) { @@ -1249,7 +1249,7 @@ shutdown :: proc(sd: Socket, how: int) -> (Errno) { if result < 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index d9efe0902..66688d224 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -438,7 +438,7 @@ close :: proc(fd: Handle) -> Errno { if result == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } // If you read or write more than `INT_MAX` bytes, FreeBSD returns `EINVAL`. @@ -495,7 +495,7 @@ rename :: proc(old_path, new_path: string) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } remove :: proc(path: string) -> Errno { @@ -505,7 +505,7 @@ remove :: proc(path: string) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { @@ -515,7 +515,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } remove_directory :: proc(path: string) -> Errno { @@ -525,7 +525,7 @@ remove_directory :: proc(path: string) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } is_file_handle :: proc(fd: Handle) -> bool { @@ -654,7 +654,7 @@ _closedir :: proc(dirp: Dir) -> Errno { if rc != 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } @private @@ -803,7 +803,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } exit :: proc "contextless" (code: int) -> ! { diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index 784ae1135..e71500b6f 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -208,7 +208,7 @@ close :: proc(fd: Handle) -> Errno { if result == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } // In practice a read/write call would probably never read/write these big buffers all at once, @@ -321,7 +321,7 @@ _closedir :: proc(dirp: Dir) -> Errno { if rc != 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } @private diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index bd55a229b..038aafff3 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -529,7 +529,7 @@ personality :: proc(persona: u64) -> (Errno) { if res == -1 { return _get_errno(res) } - return ERROR_NONE + return nil } fork :: proc() -> (Pid, Errno) { @@ -814,7 +814,7 @@ _closedir :: proc(dirp: Dir) -> Errno { if rc != 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } @private @@ -930,7 +930,7 @@ set_env :: proc(key, value: string) -> Errno { if res < 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } unset_env :: proc(key: string) -> Errno { @@ -940,7 +940,7 @@ unset_env :: proc(key: string) -> Errno { if res < 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } get_current_directory :: proc() -> string { @@ -971,7 +971,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { if res < 0 { return _get_errno(res) } - return ERROR_NONE + return nil } exit :: proc "contextless" (code: int) -> ! { @@ -1042,7 +1042,7 @@ bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { if result < 0 { return _get_errno(result) } - return ERROR_NONE + return nil } @@ -1051,7 +1051,7 @@ connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { if result < 0 { return _get_errno(result) } - return ERROR_NONE + return nil } accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Errno) { @@ -1067,7 +1067,7 @@ listen :: proc(sd: Socket, backlog: int) -> (Errno) { if result < 0 { return _get_errno(result) } - return ERROR_NONE + return nil } setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> (Errno) { @@ -1075,7 +1075,7 @@ setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: if result < 0 { return _get_errno(result) } - return ERROR_NONE + return nil } @@ -1117,7 +1117,7 @@ shutdown :: proc(sd: Socket, how: int) -> (Errno) { if result < 0 { return _get_errno(result) } - return ERROR_NONE + return nil } fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index 3de440542..efa7151f4 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -496,7 +496,7 @@ close :: proc(fd: Handle) -> Errno { if result == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } // We set a max of 1GB to keep alignment and to be safe. @@ -549,7 +549,7 @@ rename :: proc(old_path, new_path: string) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } remove :: proc(path: string) -> Errno { @@ -559,7 +559,7 @@ remove :: proc(path: string) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { @@ -569,7 +569,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } remove_directory :: proc(path: string) -> Errno { @@ -579,7 +579,7 @@ remove_directory :: proc(path: string) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } is_file_handle :: proc(fd: Handle) -> bool { @@ -719,7 +719,7 @@ _closedir :: proc(dirp: Dir) -> Errno { if rc != 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } @private @@ -856,7 +856,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } exit :: proc "contextless" (code: int) -> ! { diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index f1ad9ab38..20a7a9cbd 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -419,7 +419,7 @@ close :: proc(fd: Handle) -> Errno { if result == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } // If you read or write more than `SSIZE_MAX` bytes, OpenBSD returns `EINVAL`. @@ -476,7 +476,7 @@ rename :: proc(old_path, new_path: string) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } remove :: proc(path: string) -> Errno { @@ -486,7 +486,7 @@ remove :: proc(path: string) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { @@ -496,7 +496,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } remove_directory :: proc(path: string) -> Errno { @@ -506,7 +506,7 @@ remove_directory :: proc(path: string) -> Errno { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } is_file_handle :: proc(fd: Handle) -> bool { @@ -638,7 +638,7 @@ _closedir :: proc(dirp: Dir) -> Errno { if rc != 0 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } @private @@ -760,7 +760,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { if res == -1 { return Errno(get_last_error()) } - return ERROR_NONE + return nil } exit :: proc "contextless" (code: int) -> ! { diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index f2c5b62b4..f14cc2893 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -224,7 +224,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { if err != nil { return 0, Platform_Error(err) } - return i64(stat.size), 0 + return i64(stat.size), nil } diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 52f7062a0..afba3c3b4 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -71,11 +71,11 @@ get_last_error :: proc "contextless" () -> Error { last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { file_info: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(win32.HANDLE(fd), &file_info) { - return 0, Platform_Error(win32.GetLastError()) + return 0, get_last_error() } lo := File_Time(file_info.ftLastWriteTime.dwLowDateTime) hi := File_Time(file_info.ftLastWriteTime.dwHighDateTime) - return lo | hi << 32, ERROR_NONE + return lo | hi << 32, nil } last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { @@ -83,12 +83,12 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { wide_path := win32.utf8_to_wstring(name) if !win32.GetFileAttributesExW(wide_path, win32.GetFileExInfoStandard, &data) { - return 0, Platform_Error(win32.GetLastError()) + return 0, get_last_error() } l := File_Time(data.ftLastWriteTime.dwLowDateTime) h := File_Time(data.ftLastWriteTime.dwHighDateTime) - return l | h << 32, ERROR_NONE + return l | h << 32, nil } diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index d584749cc..72dd3eabd 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -19,7 +19,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa for { n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) if n == 0 { - return "", Platform_Error(win32.GetLastError()) + return "", get_last_error() } if n <= u32(len(buf)) { return win32.utf16_to_utf8(buf[:n], allocator) or_else "", ERROR_NONE @@ -54,7 +54,7 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al fd: win32.WIN32_FIND_DATAW sh := win32.FindFirstFileW(wname, &fd) if sh == win32.INVALID_HANDLE_VALUE { - e = Platform_Error(win32.GetLastError()) + e = get_last_error() return } win32.FindClose(sh) @@ -64,7 +64,7 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil) if h == win32.INVALID_HANDLE_VALUE { - e = Platform_Error(win32.GetLastError()) + e = get_last_error() return } defer win32.CloseHandle(h) @@ -134,13 +134,10 @@ cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { } @(private) -cleanpath_from_handle :: proc(fd: Handle) -> (string, Errno) { +cleanpath_from_handle :: proc(fd: Handle) -> (s: string, err: Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) - buf, err := cleanpath_from_handle_u16(fd, context.temp_allocator) - if err != 0 { - return "", err - } - return win32.utf16_to_utf8(buf, context.allocator) or_else "", err + buf := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return + return win32.utf16_to_utf8(buf, context.allocator) } @(private) cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ([]u16, Errno) { @@ -151,7 +148,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ( n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0) if n == 0 { - return nil, Platform_Error(win32.GetLastError()) + return nil, get_last_error() } buf := make([]u16, max(n, win32.DWORD(260))+1, allocator) buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0) @@ -273,14 +270,14 @@ file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Errno) { d: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(h, &d) { - err := Platform_Error(win32.GetLastError()) + err := get_last_error() return {}, err } ti: win32.FILE_ATTRIBUTE_TAG_INFO if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) { - err := Platform_Error(win32.GetLastError()) + err := get_last_error() if err != ERROR_INVALID_PARAMETER { return {}, err } diff --git a/core/os/stream.odin b/core/os/stream.odin index 9a168b95c..48100a425 100644 --- a/core/os/stream.odin +++ b/core/os/stream.odin @@ -27,7 +27,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, case .Read: n_int, os_err = read(fd, p) n = i64(n_int) - if n == 0 && os_err == 0 { + if n == 0 && os_err == nil { err = .EOF } @@ -35,21 +35,21 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Haiku) { n_int, os_err = read_at(fd, p, offset) n = i64(n_int) - if n == 0 && os_err == 0 { + if n == 0 && os_err == nil { err = .EOF } } case .Write: n_int, os_err = write(fd, p) n = i64(n_int) - if n == 0 && os_err == 0 { + if n == 0 && os_err == nil { err = .EOF } case .Write_At: when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Haiku) { n_int, os_err = write_at(fd, p, offset) n = i64(n_int) - if n == 0 && os_err == 0 { + if n == 0 && os_err == nil { err = .EOF } } @@ -67,7 +67,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, } } - if err == nil && os_err != 0 { + if err == nil && os_err != nil { when ODIN_OS == .Windows { if os_err == ERROR_HANDLE_EOF { return n, .EOF From a241168142a0e364c70f723e2d6eb7d961774ee3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:26:35 +0100 Subject: [PATCH 061/122] Clean up `err != nil` usage --- core/os/file_windows.odin | 9 ++------- core/os/os2/file_util.odin | 7 ++----- core/os/os2/stat_windows.odin | 13 +++++-------- core/os/os_darwin.odin | 15 ++++++++------- core/os/os_wasi.odin | 10 ++++------ 5 files changed, 21 insertions(+), 33 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index ab780982d..e18bfdd1f 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -531,14 +531,9 @@ ftruncate :: proc(fd: Handle, length: i64) -> (err: Errno) { } truncate :: proc(path: string, length: i64) -> (err: Errno) { - fd: Handle - fd, err = open(path, O_WRONLY|O_CREATE, 0o666) - if err != nil { - return - } + fd := open(path, O_WRONLY|O_CREATE, 0o666) or_return defer close(fd) - err = ftruncate(fd, length) - return + return ftruncate(fd, length) } diff --git a/core/os/os2/file_util.odin b/core/os/os2/file_util.odin index f79afdb73..b982afb3e 100644 --- a/core/os/os2/file_util.odin +++ b/core/os/os2/file_util.odin @@ -173,11 +173,8 @@ write_entire_file :: proc(name: string, data: []byte, perm: int, truncate := tru if truncate { flags |= O_TRUNC } - f, err := open(name, flags, perm) - if err != nil { - return err - } - _, err = write(f, data) + f := open(name, flags, perm) or_return + _, err := write(f, data) if cerr := close(f); cerr != nil && err == nil { err = cerr } diff --git a/core/os/os2/stat_windows.odin b/core/os/os2/stat_windows.odin index 3a3a3b1b4..5e66507be 100644 --- a/core/os/os2/stat_windows.odin +++ b/core/os/os2/stat_windows.odin @@ -6,25 +6,22 @@ import "core:time" import "core:strings" import win32 "core:sys/windows" -_fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) { +_fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { if f == nil || (^File_Impl)(f.impl).fd == nil { - return {}, nil + return } - path, err := _cleanpath_from_handle(f, allocator) - if err != nil { - return {}, err - } + path := _cleanpath_from_handle(f, allocator) or_return h := _handle(f) switch win32.GetFileType(h) { case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR: - fi := File_Info { + fi = File_Info { fullpath = path, name = basename(path), type = file_type(h), } - return fi, nil + return } return _file_info_from_get_file_information_by_handle(path, h, allocator) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 33151953d..d16e12341 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -644,7 +644,7 @@ get_last_error_string :: proc() -> string { } -open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) { +open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (handle: Handle, err: Errno) { isDir := is_dir_path(path) flags := flags if isDir { @@ -657,9 +657,10 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) - handle := _unix_open(cstr, i32(flags), u16(mode)) - if handle == -1 { - return INVALID_HANDLE, get_last_error() + handle = _unix_open(cstr, i32(flags), u16(mode)) + if handle == INVALID_HANDLE { + err = get_last_error() + return } /* @@ -667,14 +668,14 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno should not happen if the handle is a directory */ if mode != 0 && !isDir { - err := fchmod(handle, cast(u16)mode) + err = fchmod(handle, cast(u16)mode) if err != nil { _unix_close(handle) - return INVALID_HANDLE, err + handle = INVALID_HANDLE } } - return handle, nil + return } fchmod :: proc(fd: Handle, mode: u16) -> Errno { diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index f14cc2893..ac0bbf665 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -219,12 +219,10 @@ _processor_core_count :: proc() -> int { return 1 } -file_size :: proc(fd: Handle) -> (i64, Errno) { - stat, err := wasi.fd_filestat_get(wasi.fd_t(fd)) - if err != nil { - return 0, Platform_Error(err) - } - return i64(stat.size), nil +file_size :: proc(fd: Handle) -> (size: i64, err: Errno) { + stat := wasi.fd_filestat_get(wasi.fd_t(fd)) or_return + size = i64(stat.size) + return } From 28666414bc767c99c5d157f64e41b18b06082e42 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:37:49 +0100 Subject: [PATCH 062/122] More clean ups of ERROR_NONE and `!= nil` usage --- core/os/dir_unix.odin | 24 ++++------- core/os/dir_windows.odin | 11 +++-- core/os/env_windows.odin | 9 +++-- core/os/file_windows.odin | 16 ++++---- core/os/os.odin | 6 +-- core/os/os_darwin.odin | 80 ++++++++++++++++--------------------- core/os/os_essence.odin | 2 +- core/os/os_freebsd.odin | 54 ++++++++++++------------- core/os/os_haiku.odin | 31 +++++++-------- core/os/os_linux.odin | 84 ++++++++++++++++++--------------------- core/os/os_netbsd.odin | 76 +++++++++++++++-------------------- core/os/os_openbsd.odin | 65 ++++++++++++++---------------- core/os/os_wasi.odin | 2 - core/os/stat_unix.odin | 41 +++++-------------- core/os/stat_windows.odin | 20 +++++----- 15 files changed, 224 insertions(+), 297 deletions(-) diff --git a/core/os/dir_unix.odin b/core/os/dir_unix.odin index 58cd873ae..240e6ed8d 100644 --- a/core/os/dir_unix.odin +++ b/core/os/dir_unix.odin @@ -4,20 +4,10 @@ package os import "core:strings" read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { - dirp: Dir - dirp, err = _fdopendir(fd) - if err != ERROR_NONE { - return - } - + dirp := _fdopendir(fd) or_return defer _closedir(dirp) - dirpath: string - dirpath, err = absolute_path_from_handle(fd) - if err != ERROR_NONE { - return - } - + dirpath := absolute_path_from_handle(fd) or_return defer delete(dirpath) n := n @@ -27,8 +17,8 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F size = 100 } - dfi := make([dynamic]File_Info, 0, size, allocator) - defer if err != ERROR_NONE { + dfi := make([dynamic]File_Info, 0, size, allocator) or_return + defer if err != nil { for fi_ in dfi { file_info_delete(fi_, allocator) } @@ -39,7 +29,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F entry: Dirent end_of_stream: bool entry, err, end_of_stream = _readdir(dirp) - if err != ERROR_NONE { + if err != nil { return } else if end_of_stream { break @@ -56,7 +46,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F s: OS_Stat s, err = _lstat(fullpath) - if err != ERROR_NONE { + if err != nil { delete(fullpath, allocator) return } @@ -67,5 +57,5 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F append(&dfi, fi_) } - return dfi[:], ERROR_NONE + return dfi[:], nil } diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index 2d55db66f..1df1c2b9e 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -68,15 +68,14 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F } runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - wpath: []u16 - wpath, err = cleanpath_from_handle_u16(fd, context.temp_allocator) - if len(wpath) == 0 || err != ERROR_NONE { + wpath := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return + if len(wpath) == 0 { return } - dfi := make([dynamic]File_Info, 0, size) + dfi := make([dynamic]File_Info, 0, size) or_return - wpath_search := make([]u16, len(wpath)+3, context.temp_allocator) + wpath_search := make([]u16, len(wpath)+3, context.temp_allocator) or_return copy(wpath_search, wpath) wpath_search[len(wpath)+0] = '\\' wpath_search[len(wpath)+1] = '*' @@ -109,5 +108,5 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F } } - return dfi[:], ERROR_NONE + return dfi[:], nil } diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index 894a85bd9..04ce98638 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -18,7 +18,7 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin } runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - b := make([dynamic]u16, n, context.temp_allocator) + b, _ := make([dynamic]u16, n, context.temp_allocator) n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b))) if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND { return "", false @@ -61,13 +61,16 @@ unset_env :: proc(key: string) -> Errno { // environ returns a copy of strings representing the environment, in the form "key=value" // NOTE: the slice of strings and the strings with be allocated using the supplied allocator environ :: proc(allocator := context.allocator) -> []string { - envs := cast([^]win32.WCHAR)(win32.GetEnvironmentStringsW()) + envs := ([^]win32.WCHAR)(win32.GetEnvironmentStringsW()) if envs == nil { return nil } defer win32.FreeEnvironmentStringsW(envs) - r := make([dynamic]string, 0, 50, allocator) + r, err := make([dynamic]string, 0, 50, allocator) + if err != nil { + return nil + } for from, i := 0, 0; true; i += 1 { if c := envs[i]; c == 0 { if i <= from { diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index e18bfdd1f..8bfd9276d 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -52,7 +52,7 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn wide_path := win32.utf8_to_wstring(path) handle := Handle(win32.CreateFileW(wide_path, access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL|win32.FILE_FLAG_BACKUP_SEMANTICS, nil)) if handle != INVALID_HANDLE { - return handle, ERROR_NONE + return handle, nil } err := get_last_error() @@ -77,7 +77,7 @@ flush :: proc(fd: Handle) -> (err: Errno) { write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } single_write_length: win32.DWORD @@ -94,7 +94,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { } total_write += i64(single_write_length) } - return int(total_write), ERROR_NONE + return int(total_write), nil } @(private="file") @@ -150,7 +150,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } handle := win32.HANDLE(fd) @@ -176,7 +176,7 @@ read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Errno) { if bytes_read == 0 { return 0, ERROR_HANDLE_EOF } else { - return int(bytes_read), ERROR_NONE + return int(bytes_read), nil } } else { return 0, get_last_error() @@ -204,7 +204,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { err := get_last_error() return 0, err } - return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE + return i64(hi)<<32 + i64(dw_ptr), nil } file_size :: proc(fd: Handle) -> (i64, Errno) { @@ -377,7 +377,7 @@ get_current_directory :: proc(allocator := context.allocator) -> string { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) sz_utf16 := win32.GetCurrentDirectoryW(0, nil) - dir_buf_wstr := make([]u16, sz_utf16, context.temp_allocator) // the first time, it _includes_ the NUL. + dir_buf_wstr, _ := make([]u16, sz_utf16, context.temp_allocator) // the first time, it _includes_ the NUL. sz_utf16 = win32.GetCurrentDirectoryW(win32.DWORD(len(dir_buf_wstr)), raw_data(dir_buf_wstr)) assert(int(sz_utf16)+1 == len(dir_buf_wstr)) // the second time, it _excludes_ the NUL. @@ -458,7 +458,7 @@ fix_long_path :: proc(path: string) -> string { prefix :: `\\?` - path_buf := make([]byte, len(prefix)+len(path)+len(`\`), context.temp_allocator) + path_buf, _ := make([]byte, len(prefix)+len(path)+len(`\`), context.temp_allocator) copy(path_buf, prefix) n := len(path) r, w := 0, len(prefix) diff --git a/core/os/os.odin b/core/os/os.odin index 7bdef0e6f..d8c0ef658 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -145,13 +145,13 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator, return nil, true } - data = make([]byte, int(length), allocator, loc) - if data == nil { + data, err = make([]byte, int(length), allocator, loc) + if data == nil || err != nil { return nil, false } bytes_read, read_err := read_full(fd, data) - if read_err != ERROR_NONE { + if read_err != nil { delete(data) return nil, false } diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index d16e12341..a1478e99d 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -698,7 +698,7 @@ MAX_RW :: 1 << 30 write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_write := min(c.size_t(len(data)), MAX_RW) @@ -707,12 +707,12 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_written < 0 { return -1, Errno(get_last_error()) } - return bytes_written, ERROR_NONE + return bytes_written, nil } read :: proc(fd: Handle, data: []u8) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_read := min(c.size_t(len(data)), MAX_RW) @@ -721,12 +721,12 @@ read :: proc(fd: Handle, data: []u8) -> (int, Errno) { if bytes_read < 0 { return -1, Errno(get_last_error()) } - return bytes_read, ERROR_NONE + return bytes_read, nil } read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_read := min(c.size_t(len(data)), MAX_RW) @@ -735,12 +735,12 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { if bytes_read < 0 { return -1, Errno(get_last_error()) } - return bytes_read, ERROR_NONE + return bytes_read, nil } write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_write := min(c.size_t(len(data)), MAX_RW) @@ -749,7 +749,7 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { if bytes_written < 0 { return -1, Errno(get_last_error()) } - return bytes_written, ERROR_NONE + return bytes_written, nil } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { @@ -776,22 +776,16 @@ stdin: Handle = 0 // get_std_handle(win32.STD_INPUT_HANDLE); stdout: Handle = 1 // get_std_handle(win32.STD_OUTPUT_HANDLE); stderr: Handle = 2 // get_std_handle(win32.STD_ERROR_HANDLE); -last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { - s, err := _fstat(fd) - if err != ERROR_NONE { - return 0, err - } +last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Errno) { + s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds - return File_Time(modified), ERROR_NONE + return File_Time(modified), nil } -last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { - s, err := _stat(name) - if err != ERROR_NONE { - return 0, err - } +last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Errno) { + s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds - return File_Time(modified), ERROR_NONE + return File_Time(modified), nil } @@ -801,7 +795,7 @@ is_path_separator :: proc(r: rune) -> bool { is_file_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return false } return S_ISREG(s.mode) @@ -815,7 +809,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { } else { s, err = _lstat(path) } - if err != ERROR_NONE { + if err != nil { return false } return S_ISREG(s.mode) @@ -824,7 +818,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { is_dir_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return false } return S_ISDIR(s.mode) @@ -838,7 +832,7 @@ is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { } else { s, err = _lstat(path) } - if err != ERROR_NONE { + if err != nil { return false } return S_ISDIR(s.mode) @@ -881,7 +875,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { if result == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -894,7 +888,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { if result == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -904,7 +898,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { if result == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -913,7 +907,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Errno) { if dirp == cast(Dir)nil { return nil, Errno(get_last_error()) } - return dirp, ERROR_NONE + return dirp, nil } @private @@ -939,7 +933,6 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) err = Errno(get_last_error()) return } - err = ERROR_NONE if result == nil { end_of_stream = true @@ -968,20 +961,15 @@ _readlink :: proc(path: string) -> (string, Errno) { delete(buf) buf = make([]byte, bufsz) } else { - return strings.string_from_ptr(&buf[0], rc), ERROR_NONE + return strings.string_from_ptr(&buf[0], rc), nil } } } -absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { +absolute_path_from_handle :: proc(fd: Handle) -> (path: string, err: Errno) { buf: [DARWIN_MAXPATHLEN]byte - _, err := fcntl(int(fd), F_GETPATH, int(uintptr(&buf[0]))) - if err != ERROR_NONE { - return "", err - } - - path := strings.clone_from_cstring(cstring(&buf[0])) - return path, err + _ = fcntl(int(fd), F_GETPATH, int(uintptr(&buf[0]))) or_return + return strings.clone_from_cstring(cstring(&buf[0])) } absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { @@ -1002,7 +990,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path_cstr := cast(cstring)path_ptr path = strings.clone(string(path_cstr)) - return path, ERROR_NONE + return path, nil } access :: proc(path: string, mask: int) -> bool { @@ -1162,7 +1150,7 @@ socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Errno) { if result < 0 { return 0, Errno(get_last_error()) } - return Socket(result), ERROR_NONE + return Socket(result), nil } connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { @@ -1186,7 +1174,7 @@ accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Errno) { if result < 0 { return 0, Errno(get_last_error()) } - return Socket(result), ERROR_NONE + return Socket(result), nil } listen :: proc(sd: Socket, backlog: int) -> (Errno) { @@ -1218,7 +1206,7 @@ recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_siz if result < 0 { return 0, Errno(get_last_error()) } - return u32(result), ERROR_NONE + return u32(result), nil } recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { @@ -1226,7 +1214,7 @@ recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { if result < 0 { return 0, Errno(get_last_error()) } - return u32(result), ERROR_NONE + return u32(result), nil } sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: socklen_t) -> (u32, Errno) { @@ -1234,7 +1222,7 @@ sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: soc if result < 0 { return 0, Errno(get_last_error()) } - return u32(result), ERROR_NONE + return u32(result), nil } send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { @@ -1242,7 +1230,7 @@ send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { if result < 0 { return 0, Errno(get_last_error()) } - return u32(result), ERROR_NONE + return u32(result), nil } shutdown :: proc(sd: Socket, how: int) -> (Errno) { @@ -1258,5 +1246,5 @@ fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { if result < 0 { return 0, Errno(get_last_error()) } - return int(result), ERROR_NONE + return int(result), nil } diff --git a/core/os/os_essence.odin b/core/os/os_essence.odin index 98abb432d..7509785bc 100644 --- a/core/os/os_essence.odin +++ b/core/os/os_essence.odin @@ -5,7 +5,7 @@ import "core:sys/es" Handle :: distinct int _Platform_Error :: enum i32 {NONE} -ERROR_NONE :: Errno(es.SUCCESS) +// ERROR_NONE :: Errno(es.SUCCESS) O_RDONLY :: 0x1 O_WRONLY :: 0x2 diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 66688d224..c64e5147f 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -430,7 +430,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err if handle == -1 { return INVALID_HANDLE, Errno(get_last_error()) } - return handle, ERROR_NONE + return handle, nil } close :: proc(fd: Handle) -> Errno { @@ -455,12 +455,12 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_read == -1 { return -1, Errno(get_last_error()) } - return int(bytes_read), ERROR_NONE + return int(bytes_read), nil } write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_write := min(c.size_t(len(data)), MAX_RW) @@ -468,7 +468,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_written == -1 { return -1, Errno(get_last_error()) } - return int(bytes_written), ERROR_NONE + return int(bytes_written), nil } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { @@ -476,15 +476,14 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { if res == -1 { return -1, Errno(get_last_error()) } - return res, ERROR_NONE + return res, nil } -file_size :: proc(fd: Handle) -> (i64, Errno) { - s, err := _fstat(fd) - if err != ERROR_NONE { - return -1, err - } - return s.size, ERROR_NONE +file_size :: proc(fd: Handle) -> (size: i64, err: Errno) { + size = -1 + s := _fstat(fd) or_return + size = s.size + return } rename :: proc(old_path, new_path: string) -> Errno { @@ -530,7 +529,7 @@ remove_directory :: proc(path: string) -> Errno { is_file_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return false } return S_ISREG(s.mode) @@ -544,7 +543,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { } else { s, err = _lstat(path) } - if err != ERROR_NONE { + if err != nil { return false } return S_ISREG(s.mode) @@ -552,7 +551,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { is_dir_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return false } return S_ISDIR(s.mode) @@ -566,7 +565,7 @@ is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { } else { s, err = _lstat(path) } - if err != ERROR_NONE { + if err != nil { return false } return S_ISDIR(s.mode) @@ -587,20 +586,20 @@ last_write_time_by_name :: proc(name: string) -> File_Time {} */ last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return 0, err } modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds - return File_Time(modified), ERROR_NONE + return File_Time(modified), nil } last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { s, err := _stat(name) - if err != ERROR_NONE { + if err != nil { return 0, err } modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds - return File_Time(modified), ERROR_NONE + return File_Time(modified), nil } @private @@ -612,7 +611,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { if result == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -626,7 +625,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { if res == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -636,7 +635,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { if result == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -645,7 +644,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Errno) { if dirp == cast(Dir)nil { return nil, Errno(get_last_error()) } - return dirp, ERROR_NONE + return dirp, nil } @private @@ -671,7 +670,6 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) err = Errno(get_last_error()) return } - err = ERROR_NONE if result == nil { end_of_stream = true @@ -699,7 +697,7 @@ _readlink :: proc(path: string) -> (string, Errno) { delete(buf) buf = make([]byte, bufsz) } else { - return strings.string_from_ptr(&buf[0], rc), ERROR_NONE + return strings.string_from_ptr(&buf[0], rc), nil } } @@ -725,7 +723,7 @@ absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { } path := strings.clone_from_cstring_bounded(cast(cstring)&kinfo.path[0], len(kinfo.path)) - return path, ERROR_NONE + return path, nil } absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { @@ -746,7 +744,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path = strings.clone(string(cstring(path_ptr))) - return path, ERROR_NONE + return path, nil } access :: proc(path: string, mask: int) -> (bool, Errno) { @@ -757,7 +755,7 @@ access :: proc(path: string, mask: int) -> (bool, Errno) { if result == -1 { return false, Errno(get_last_error()) } - return true, ERROR_NONE + return true, nil } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index e71500b6f..cc748b82b 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -190,7 +190,7 @@ fork :: proc() -> (Pid, Errno) { if pid == -1 { return Pid(-1), Errno(get_last_error()) } - return Pid(pid), ERROR_NONE + return Pid(pid), nil } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { @@ -200,7 +200,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err if handle == -1 { return INVALID_HANDLE, Errno(get_last_error()) } - return handle, ERROR_NONE + return handle, nil } close :: proc(fd: Handle) -> Errno { @@ -224,12 +224,12 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_read == -1 { return -1, Errno(get_last_error()) } - return int(bytes_read), ERROR_NONE + return int(bytes_read), nil } write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_write := min(c.size_t(len(data)), MAX_RW) @@ -237,7 +237,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_written == -1 { return -1, Errno(get_last_error()) } - return int(bytes_written), ERROR_NONE + return int(bytes_written), nil } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { @@ -245,15 +245,15 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { if res == -1 { return -1, Errno(get_last_error()) } - return res, ERROR_NONE + return res, nil } file_size :: proc(fd: Handle) -> (i64, Errno) { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return -1, err } - return s.size, ERROR_NONE + return s.size, nil } // "Argv" arguments converted to Odin strings @@ -278,7 +278,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { if res == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -292,7 +292,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { if res == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -303,7 +303,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { if res == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -312,7 +312,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Errno) { if dirp == cast(Dir)nil { return nil, Errno(get_last_error()) } - return dirp, ERROR_NONE + return dirp, nil } @private @@ -338,7 +338,6 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) err = Errno(get_last_error()) return } - err = ERROR_NONE if result == nil { end_of_stream = true @@ -365,7 +364,7 @@ _readlink :: proc(path: string) -> (string, Errno) { delete(buf) buf = make([]byte, bufsz) } else { - return strings.string_from_ptr(&buf[0], rc), ERROR_NONE + return strings.string_from_ptr(&buf[0], rc), nil } } } @@ -392,7 +391,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path_cstr := cstring(path_ptr) path = strings.clone(string(path_cstr)) - return path, ERROR_NONE + return path, nil } access :: proc(path: string, mask: int) -> (bool, Errno) { @@ -402,7 +401,7 @@ access :: proc(path: string, mask: int) -> (bool, Errno) { if res == -1 { return false, Errno(get_last_error()) } - return true, ERROR_NONE + return true, nil } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 038aafff3..3d24e2258 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -537,7 +537,7 @@ fork :: proc() -> (Pid, Errno) { if pid == -1 { return -1, _get_errno(pid) } - return Pid(pid), ERROR_NONE + return Pid(pid), nil } execvp :: proc(path: string, args: []string) -> Errno { @@ -562,7 +562,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0o000) -> (Handle, if handle < 0 { return INVALID_HANDLE, _get_errno(handle) } - return Handle(handle), ERROR_NONE + return Handle(handle), nil } close :: proc(fd: Handle) -> Errno { @@ -580,7 +580,7 @@ MAX_RW :: 1 << 30 read :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_read := min(uint(len(data)), MAX_RW) @@ -589,12 +589,12 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_read < 0 { return -1, _get_errno(bytes_read) } - return bytes_read, ERROR_NONE + return bytes_read, nil } write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_write := min(uint(len(data)), MAX_RW) @@ -603,12 +603,12 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_written < 0 { return -1, _get_errno(bytes_written) } - return bytes_written, ERROR_NONE + return bytes_written, nil } read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_read := min(uint(len(data)), MAX_RW) @@ -617,12 +617,12 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { if bytes_read < 0 { return -1, _get_errno(bytes_read) } - return bytes_read, ERROR_NONE + return bytes_read, nil } write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_write := min(uint(len(data)), MAX_RW) @@ -631,7 +631,7 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { if bytes_written < 0 { return -1, _get_errno(bytes_written) } - return bytes_written, ERROR_NONE + return bytes_written, nil } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { @@ -639,7 +639,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { if res < 0 { return -1, _get_errno(int(res)) } - return i64(res), ERROR_NONE + return i64(res), nil } file_size :: proc(fd: Handle) -> (i64, Errno) { @@ -649,7 +649,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { if result < 0 { return 0, _get_errno(result) } - return max(s.size, 0), ERROR_NONE + return max(s.size, 0), nil } rename :: proc(old_path, new_path: string) -> Errno { @@ -679,7 +679,7 @@ remove_directory :: proc(path: string) -> Errno { is_file_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return false } return S_ISREG(s.mode) @@ -693,7 +693,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { } else { s, err = _lstat(path) } - if err != ERROR_NONE { + if err != nil { return false } return S_ISREG(s.mode) @@ -702,7 +702,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { is_dir_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return false } return S_ISDIR(s.mode) @@ -716,7 +716,7 @@ is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { } else { s, err = _lstat(path) } - if err != ERROR_NONE { + if err != nil { return false } return S_ISDIR(s.mode) @@ -742,22 +742,16 @@ stderr: Handle = 2 last_write_time :: proc(fd: Handle) -> File_Time {} last_write_time_by_name :: proc(name: string) -> File_Time {} */ -last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { - s, err := _fstat(fd) - if err != ERROR_NONE { - return 0, err - } +last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Errno) { + s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds - return File_Time(modified), ERROR_NONE + return File_Time(modified), nil } -last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { - s, err := _stat(name) - if err != ERROR_NONE { - return 0, err - } +last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Errno) { + s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds - return File_Time(modified), ERROR_NONE + return File_Time(modified), nil } @private @@ -771,7 +765,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { if result < 0 { return s, _get_errno(result) } - return s, ERROR_NONE + return s, nil } @private @@ -785,7 +779,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { if result < 0 { return s, _get_errno(result) } - return s, ERROR_NONE + return s, nil } @private @@ -796,7 +790,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { if result < 0 { return s, _get_errno(result) } - return s, ERROR_NONE + return s, nil } @private @@ -805,7 +799,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Errno) { if dirp == cast(Dir)nil { return nil, Errno(get_last_error()) } - return dirp, ERROR_NONE + return dirp, nil } @private @@ -831,7 +825,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) err = Errno(get_last_error()) return } - err = ERROR_NONE + err = nil if result == nil { end_of_stream = true @@ -860,7 +854,7 @@ _readlink :: proc(path: string) -> (string, Errno) { delete(buf) buf = make([]byte, bufsz) } else { - return strings.string_from_ptr(&buf[0], rc), ERROR_NONE + return strings.string_from_ptr(&buf[0], rc), nil } } } @@ -892,7 +886,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path = strings.clone(string(cstring(path_ptr))) - return path, ERROR_NONE + return path, nil } access :: proc(path: string, mask: int) -> (bool, Errno) { @@ -902,7 +896,7 @@ access :: proc(path: string, mask: int) -> (bool, Errno) { if result < 0 { return false, _get_errno(result) } - return true, ERROR_NONE + return true, nil } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { @@ -1034,7 +1028,7 @@ socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Errno) { if result < 0 { return 0, _get_errno(result) } - return Socket(result), ERROR_NONE + return Socket(result), nil } bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { @@ -1059,7 +1053,7 @@ accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Errno) { if result < 0 { return 0, _get_errno(result) } - return Socket(result), ERROR_NONE + return Socket(result), nil } listen :: proc(sd: Socket, backlog: int) -> (Errno) { @@ -1084,7 +1078,7 @@ recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_siz if result < 0 { return 0, _get_errno(int(result)) } - return u32(result), ERROR_NONE + return u32(result), nil } recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { @@ -1092,7 +1086,7 @@ recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { if result < 0 { return 0, _get_errno(int(result)) } - return u32(result), ERROR_NONE + return u32(result), nil } @@ -1101,7 +1095,7 @@ sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: soc if result < 0 { return 0, _get_errno(int(result)) } - return u32(result), ERROR_NONE + return u32(result), nil } send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { @@ -1109,7 +1103,7 @@ send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { if result < 0 { return 0, _get_errno(int(result)) } - return u32(result), ERROR_NONE + return u32(result), nil } shutdown :: proc(sd: Socket, how: int) -> (Errno) { @@ -1125,7 +1119,7 @@ fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { if result < 0 { return 0, _get_errno(result) } - return result, ERROR_NONE + return result, nil } poll :: proc(fds: []pollfd, timeout: int) -> (int, Errno) { @@ -1133,7 +1127,7 @@ poll :: proc(fds: []pollfd, timeout: int) -> (int, Errno) { if result < 0 { return 0, _get_errno(result) } - return result, ERROR_NONE + return result, nil } ppoll :: proc(fds: []pollfd, timeout: ^unix.timespec, sigmask: ^sigset_t) -> (int, Errno) { @@ -1141,5 +1135,5 @@ ppoll :: proc(fds: []pollfd, timeout: ^unix.timespec, sigmask: ^sigset_t) -> (in if result < 0 { return 0, _get_errno(result) } - return result, ERROR_NONE + return result, nil } diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index efa7151f4..ed9d81dfe 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -488,7 +488,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err if handle == -1 { return INVALID_HANDLE, Errno(get_last_error()) } - return handle, ERROR_NONE + return handle, nil } close :: proc(fd: Handle) -> Errno { @@ -509,12 +509,12 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_read == -1 { return -1, Errno(get_last_error()) } - return int(bytes_read), ERROR_NONE + return int(bytes_read), nil } write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_write := min(c.size_t(len(data)), MAX_RW) @@ -522,7 +522,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_written == -1 { return -1, Errno(get_last_error()) } - return int(bytes_written), ERROR_NONE + return int(bytes_written), nil } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { @@ -530,15 +530,14 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { if res == -1 { return -1, Errno(get_last_error()) } - return res, ERROR_NONE + return res, nil } -file_size :: proc(fd: Handle) -> (i64, Errno) { - s, err := _fstat(fd) - if err != ERROR_NONE { - return -1, err - } - return s.size, ERROR_NONE +file_size :: proc(fd: Handle) -> (size: i64, err: Errno) { + size = -1 + s := _fstat(fd) or_return + size = s.size + return } rename :: proc(old_path, new_path: string) -> Errno { @@ -584,7 +583,7 @@ remove_directory :: proc(path: string) -> Errno { is_file_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return false } return S_ISREG(s.mode) @@ -598,7 +597,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { } else { s, err = _lstat(path) } - if err != ERROR_NONE { + if err != nil { return false } return S_ISREG(s.mode) @@ -606,7 +605,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { is_dir_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return false } return S_ISDIR(s.mode) @@ -620,7 +619,7 @@ is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { } else { s, err = _lstat(path) } - if err != ERROR_NONE { + if err != nil { return false } return S_ISDIR(s.mode) @@ -641,7 +640,7 @@ fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { if result < 0 { return 0, Errno(get_last_error()) } - return int(result), ERROR_NONE + return int(result), nil } // NOTE(bill): Uses startup to initialize it @@ -650,22 +649,16 @@ stdin: Handle = 0 stdout: Handle = 1 stderr: Handle = 2 -last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { - s, err := _fstat(fd) - if err != ERROR_NONE { - return 0, err - } +last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Errno) { + s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds - return File_Time(modified), ERROR_NONE + return File_Time(modified), nil } -last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { - s, err := _stat(name) - if err != ERROR_NONE { - return 0, err - } +last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Errno) { + s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds - return File_Time(modified), ERROR_NONE + return File_Time(modified), nil } @private @@ -677,7 +670,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { if result == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -691,7 +684,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { if res == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -701,7 +694,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { if result == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -710,7 +703,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Errno) { if dirp == cast(Dir)nil { return nil, Errno(get_last_error()) } - return dirp, ERROR_NONE + return dirp, nil } @private @@ -736,7 +729,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) err = Errno(get_last_error()) return } - err = ERROR_NONE + err = nil if result == nil { end_of_stream = true @@ -764,22 +757,17 @@ _readlink :: proc(path: string) -> (string, Errno) { delete(buf) buf = make([]byte, bufsz) } else { - return strings.string_from_ptr(&buf[0], rc), ERROR_NONE + return strings.string_from_ptr(&buf[0], rc), nil } } return "", Errno{} } -absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { +absolute_path_from_handle :: proc(fd: Handle) -> (path: string, err: Errno) { buf: [MAX_PATH]byte - _, err := fcntl(int(fd), F_GETPATH, int(uintptr(&buf[0]))) - if err != ERROR_NONE { - return "", err - } - - path := strings.clone_from_cstring(cstring(&buf[0])) - return path, err + _ = fcntl(int(fd), F_GETPATH, int(uintptr(&buf[0]))) or_return + return strings.clone_from_cstring(cstring(&buf[0])) } absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { @@ -799,7 +787,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path = strings.clone(string(cstring(path_ptr))) - return path, ERROR_NONE + return path, nil } access :: proc(path: string, mask: int) -> (bool, Errno) { @@ -810,7 +798,7 @@ access :: proc(path: string, mask: int) -> (bool, Errno) { if result == -1 { return false, Errno(get_last_error()) } - return true, ERROR_NONE + return true, nil } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 20a7a9cbd..9ecdbbc98 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -401,7 +401,7 @@ fork :: proc() -> (Pid, Errno) { if pid == -1 { return Pid(-1), Errno(get_last_error()) } - return Pid(pid), ERROR_NONE + return Pid(pid), nil } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { @@ -411,7 +411,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err if handle == -1 { return INVALID_HANDLE, Errno(get_last_error()) } - return handle, ERROR_NONE + return handle, nil } close :: proc(fd: Handle) -> Errno { @@ -436,12 +436,12 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_read == -1 { return -1, Errno(get_last_error()) } - return int(bytes_read), ERROR_NONE + return int(bytes_read), nil } write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE + return 0, nil } to_write := min(c.size_t(len(data)), MAX_RW) @@ -449,7 +449,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if bytes_written == -1 { return -1, Errno(get_last_error()) } - return int(bytes_written), ERROR_NONE + return int(bytes_written), nil } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { @@ -457,15 +457,14 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { if res == -1 { return -1, Errno(get_last_error()) } - return res, ERROR_NONE + return res, nil } -file_size :: proc(fd: Handle) -> (i64, Errno) { - s, err := _fstat(fd) - if err != ERROR_NONE { - return -1, err - } - return s.size, ERROR_NONE +file_size :: proc(fd: Handle) -> (size: i64, err: Errno) { + size = -1 + s := _fstat(fd) or_return + size = s.size + return } rename :: proc(old_path, new_path: string) -> Errno { @@ -511,7 +510,7 @@ remove_directory :: proc(path: string) -> Errno { is_file_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return false } return S_ISREG(s.mode) @@ -525,7 +524,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { } else { s, err = _lstat(path) } - if err != ERROR_NONE { + if err != nil { return false } return S_ISREG(s.mode) @@ -533,7 +532,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { is_dir_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) - if err != ERROR_NONE { + if err != nil { return false } return S_ISDIR(s.mode) @@ -547,7 +546,7 @@ is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { } else { s, err = _lstat(path) } - if err != ERROR_NONE { + if err != nil { return false } return S_ISDIR(s.mode) @@ -566,22 +565,16 @@ stderr: Handle = 2 last_write_time :: proc(fd: Handle) -> File_Time {} last_write_time_by_name :: proc(name: string) -> File_Time {} */ -last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { - s, err := _fstat(fd) - if err != ERROR_NONE { - return 0, err - } +last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Errno) { + s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds - return File_Time(modified), ERROR_NONE + return File_Time(modified), nil } -last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { - s, err := _stat(name) - if err != ERROR_NONE { - return 0, err - } +last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Errno) { + s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds - return File_Time(modified), ERROR_NONE + return File_Time(modified), nil } @private @@ -595,7 +588,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { if res == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -609,7 +602,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { if res == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -620,7 +613,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { if res == -1 { return s, Errno(get_last_error()) } - return s, ERROR_NONE + return s, nil } @private @@ -629,7 +622,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Errno) { if dirp == cast(Dir)nil { return nil, Errno(get_last_error()) } - return dirp, ERROR_NONE + return dirp, nil } @private @@ -655,7 +648,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) err = Errno(get_last_error()) return } - err = ERROR_NONE + err = nil if result == nil { end_of_stream = true @@ -682,7 +675,7 @@ _readlink :: proc(path: string) -> (string, Errno) { delete(buf) buf = make([]byte, bufsz) } else { - return strings.string_from_ptr(&buf[0], rc), ERROR_NONE + return strings.string_from_ptr(&buf[0], rc), nil } } } @@ -709,7 +702,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path = strings.clone(string(cstring(path_ptr))) - return path, ERROR_NONE + return path, nil } access :: proc(path: string, mask: int) -> (bool, Errno) { @@ -719,7 +712,7 @@ access :: proc(path: string, mask: int) -> (bool, Errno) { if res == -1 { return false, Errno(get_last_error()) } - return true, ERROR_NONE + return true, nil } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index ac0bbf665..9da053796 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -8,8 +8,6 @@ _Platform_Error :: wasi.errno_t INVALID_HANDLE :: -1 -// ERROR_NONE :: Errno(wasi.errno_t.SUCCESS) // that is a weird error code. Probably better to remap it - O_RDONLY :: 0x00000 O_WRONLY :: 0x00001 O_RDWR :: 0x00002 diff --git a/core/os/stat_unix.odin b/core/os/stat_unix.odin index 3bd62dfc7..e123dca23 100644 --- a/core/os/stat_unix.odin +++ b/core/os/stat_unix.odin @@ -101,54 +101,31 @@ path_base :: proc(path: string) -> string { lstat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, err: Errno) { - context.allocator = allocator - s: OS_Stat - s, err = _lstat(name) - if err != ERROR_NONE { - return fi, err - } + s := _lstat(name) or_return _fill_file_info_from_stat(&fi, s) - fi.fullpath, err = absolute_path_from_relative(name) - if err != ERROR_NONE { - return - } + fi.fullpath = absolute_path_from_relative(name) or_return fi.name = path_base(fi.fullpath) - return fi, ERROR_NONE + return } stat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, err: Errno) { context.allocator = allocator - s: OS_Stat - s, err = _stat(name) - if err != ERROR_NONE { - return fi, err - } + s := _stat(name) or_return _fill_file_info_from_stat(&fi, s) - fi.fullpath, err = absolute_path_from_relative(name) - if err != ERROR_NONE { - return - } + fi.fullpath = absolute_path_from_relative(name) or_return fi.name = path_base(fi.fullpath) - return fi, ERROR_NONE + return } fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err: Errno) { - context.allocator = allocator - s: OS_Stat - s, err = _fstat(fd) - if err != ERROR_NONE { - return fi, err - } + s := _fstat(fd) or_return _fill_file_info_from_stat(&fi, s) - fi.fullpath, err = absolute_path_from_handle(fd) - if err != ERROR_NONE { - return - } + fi.fullpath = absolute_path_from_handle(fd) or_return fi.name = path_base(fi.fullpath) - return fi, ERROR_NONE + return } diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index 72dd3eabd..0c0bf51a3 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -22,7 +22,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa return "", get_last_error() } if n <= u32(len(buf)) { - return win32.utf16_to_utf8(buf[:n], allocator) or_else "", ERROR_NONE + return win32.utf16_to_utf8(buf[:n], allocator) or_else "", nil } resize(&buf, len(buf)*2) } @@ -83,15 +83,15 @@ stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) return _stat(name, attrs, allocator) } -fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, errno: Errno) { +fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err: Errno) { if fd == 0 { - return {}, ERROR_INVALID_HANDLE + err = ERROR_INVALID_HANDLE } context.allocator = allocator - path, err := cleanpath_from_handle(fd) - if err != ERROR_NONE { - return {}, err + path := cleanpath_from_handle(fd) or_return + defer if err != nil { + delete(path) } h := win32.HANDLE(fd) @@ -99,9 +99,9 @@ fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR: fi.name = basename(path) fi.mode |= file_type_mode(h) - errno = ERROR_NONE + err = nil case: - fi, errno = file_info_from_get_file_information_by_handle(path, h) + fi = file_info_from_get_file_information_by_handle(path, h) or_return } fi.fullpath = path return @@ -152,7 +152,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ( } buf := make([]u16, max(n, win32.DWORD(260))+1, allocator) buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0) - return buf[:buf_len], ERROR_NONE + return buf[:buf_len], nil } @(private) cleanpath_from_buf :: proc(buf: []u16) -> string { @@ -296,5 +296,5 @@ file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HAN windows_set_file_info_times(&fi, &d) - return fi, ERROR_NONE + return fi, nil } From def2e2e27112e4cc745afaa89a03857e01c5aabd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:44:45 +0100 Subject: [PATCH 063/122] Try to map to `General_Error` where possible --- core/os/dir_unix.odin | 1 + core/os/dir_windows.odin | 1 + core/os/env_windows.odin | 3 +++ core/os/file_windows.odin | 5 ++-- core/os/os.odin | 36 ++++++++++++++++++++++++++++- core/os/os2/errors.odin | 3 ++- core/os/os_linux.odin | 13 ++++++++++- core/os/os_windows.odin | 48 ++++++++++++++++++++++++++++++++++++++- 8 files changed, 103 insertions(+), 7 deletions(-) diff --git a/core/os/dir_unix.odin b/core/os/dir_unix.odin index 240e6ed8d..727dd1319 100644 --- a/core/os/dir_unix.odin +++ b/core/os/dir_unix.odin @@ -3,6 +3,7 @@ package os import "core:strings" +@(require_results) read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { dirp := _fdopendir(fd) or_return defer _closedir(dirp) diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index 1df1c2b9e..c96ce53f5 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -4,6 +4,7 @@ import win32 "core:sys/windows" import "core:strings" import "base:runtime" +@(require_results) read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) { // Ignore "." and ".." diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index 04ce98638..a73687a3c 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -7,6 +7,7 @@ import "base:runtime" // If the variable is found in the environment the value (which can be empty) is returned and the boolean is true // Otherwise the returned value will be empty and the boolean will be false // NOTE: the value will be allocated with the supplied allocator +@(require_results) lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { if key == "" { return @@ -33,6 +34,7 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin // It returns the value, which will be empty if the variable is not present // To distinguish between an empty value and an unset value, use lookup_env // NOTE: the value will be allocated with the supplied allocator +@(require_results) get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return @@ -60,6 +62,7 @@ unset_env :: proc(key: string) -> Errno { // environ returns a copy of strings representing the environment, in the form "key=value" // NOTE: the slice of strings and the strings with be allocated using the supplied allocator +@(require_results) environ :: proc(allocator := context.allocator) -> []string { envs := ([^]win32.WCHAR)(win32.GetEnvironmentStringsW()) if envs == nil { diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 8bfd9276d..7831aa3e6 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -11,7 +11,7 @@ is_path_separator :: proc(c: byte) -> bool { open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) { if len(path) == 0 { - return INVALID_HANDLE, ERROR_FILE_NOT_FOUND + return INVALID_HANDLE, General_Error.Not_Exist } access: u32 @@ -55,8 +55,7 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn return handle, nil } - err := get_last_error() - return INVALID_HANDLE, err + return INVALID_HANDLE, get_last_error() } close :: proc(fd: Handle) -> Errno { diff --git a/core/os/os.odin b/core/os/os.odin index d8c0ef658..3db3c5bd7 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -19,17 +19,51 @@ Platform_Error :: _Platform_Error #assert(size_of(Platform_Error) <= 4) #assert(intrinsics.type_has_nil(Platform_Error)) +General_Error :: enum u32 { + None, + + Permission_Denied, + Exist, + Not_Exist, + Closed, + + Timeout, + + Broken_Pipe, + + // Indicates that an attempt to retrieve a file's size was made, but the + // file doesn't have a size. + No_Size, + + Invalid_File, + Invalid_Dir, + Invalid_Path, + Invalid_Callback, + + Pattern_Has_Separator, + + Unsupported, +} + + Errno :: Error // alias for legacy use Error :: union #shared_nil { + General_Error, io.Error, runtime.Allocator_Error, Platform_Error, } -#assert(size_of(Error) <= 8) +#assert(size_of(Error) == 8) ERROR_NONE :: Error{} +@(require_results) +is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { + v := ferr.(Platform_Error) or_else {} + return i32(v), i32(v) != 0 +} + write_string :: proc(fd: Handle, str: string) -> (int, Errno) { return write(fd, transmute([]byte)str) } diff --git a/core/os/os2/errors.odin b/core/os/os2/errors.odin index 2b9b3528e..bc51bb1e8 100644 --- a/core/os/os2/errors.odin +++ b/core/os/os2/errors.odin @@ -42,13 +42,14 @@ Error :: union #shared_nil { ERROR_NONE :: Error{} - +@(require_results) is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { v := ferr.(Platform_Error) or_else {} return i32(v), i32(v) != 0 } +@(require_results) error_string :: proc(ferr: Error) -> string { if ferr == nil { return "" diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 3d24e2258..4d5b13930 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -521,7 +521,18 @@ _get_errno :: proc(res: int) -> Errno { // get errno from libc get_last_error :: proc "contextless" () -> Error { - return Platform_Error(__errno_location()^) + err := Platform_Error(__errno_location()^) + #partial switch err { + case .NONE: + return nil + case .EPERM: + return .Permission_Denied + case .EEXIST: + return .Exist + case .ENOENT: + return .Not_Exist + } + return err } personality :: proc(persona: u64) -> (Errno) { diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index afba3c3b4..99c28d880 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -64,7 +64,53 @@ ERROR_NEGATIVE_OFFSET :: _Platform_Error(1<<29 + 2) args := _alloc_command_line_arguments() get_last_error :: proc "contextless" () -> Error { - return Platform_Error(win32.GetLastError()) + err := win32.GetLastError() + if err == 0 { + return nil + } + switch err { + case win32.ERROR_ACCESS_DENIED, win32.ERROR_SHARING_VIOLATION: + return .Permission_Denied + + case win32.ERROR_FILE_EXISTS, win32.ERROR_ALREADY_EXISTS: + return .Exist + + case win32.ERROR_FILE_NOT_FOUND, win32.ERROR_PATH_NOT_FOUND: + return .Not_Exist + + case win32.ERROR_NO_DATA: + return .Closed + + case win32.ERROR_TIMEOUT, win32.WAIT_TIMEOUT: + return .Timeout + + case win32.ERROR_NOT_SUPPORTED: + return .Unsupported + + case win32.ERROR_HANDLE_EOF: + return .EOF + + case win32.ERROR_INVALID_HANDLE: + return .Invalid_File + + case + win32.ERROR_BAD_ARGUMENTS, + win32.ERROR_INVALID_PARAMETER, + win32.ERROR_NOT_ENOUGH_MEMORY, + win32.ERROR_NO_MORE_FILES, + win32.ERROR_LOCK_VIOLATION, + win32.ERROR_BROKEN_PIPE, + win32.ERROR_CALL_NOT_IMPLEMENTED, + win32.ERROR_INSUFFICIENT_BUFFER, + win32.ERROR_INVALID_NAME, + win32.ERROR_LOCK_FAILED, + win32.ERROR_ENVVAR_NOT_FOUND, + win32.ERROR_OPERATION_ABORTED, + win32.ERROR_IO_PENDING, + win32.ERROR_NO_UNICODE_TRANSLATION: + // fallthrough + } + return Platform_Error(err) } From 160048eaeeb622fc8532787ed43e53d3818a1657 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:46:42 +0100 Subject: [PATCH 064/122] `Errno` -> `Error` --- core/os/dir_unix.odin | 2 +- core/os/dir_windows.odin | 2 +- core/os/env_windows.odin | 4 +- core/os/file_windows.odin | 50 ++++++------ core/os/os.odin | 16 ++-- core/os/os2/errors_linux.odin | 8 +- core/os/os2/path_linux.odin | 2 +- core/os/os_darwin.odin | 148 +++++++++++++++++----------------- core/os/os_essence.odin | 26 +++--- core/os/os_js.odin | 52 ++++++------ core/os/os_linux.odin | 108 ++++++++++++------------- core/os/os_windows.odin | 4 +- core/os/stat_unix.odin | 6 +- core/os/stream.odin | 2 +- 14 files changed, 215 insertions(+), 215 deletions(-) diff --git a/core/os/dir_unix.odin b/core/os/dir_unix.odin index 727dd1319..6f6bed36d 100644 --- a/core/os/dir_unix.odin +++ b/core/os/dir_unix.odin @@ -4,7 +4,7 @@ package os import "core:strings" @(require_results) -read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { +read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Error) { dirp := _fdopendir(fd) or_return defer _closedir(dirp) diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index c96ce53f5..d6028dd7e 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -5,7 +5,7 @@ import "core:strings" import "base:runtime" @(require_results) -read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { +read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Error) { find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) { // Ignore "." and ".." if d.cFileName[0] == '.' && d.cFileName[1] == 0 { diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index a73687a3c..efd002342 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -41,7 +41,7 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string) } // set_env sets the value of the environment variable named by the key -set_env :: proc(key, value: string) -> Errno { +set_env :: proc(key, value: string) -> Error { k := win32.utf8_to_wstring(key) v := win32.utf8_to_wstring(value) @@ -52,7 +52,7 @@ set_env :: proc(key, value: string) -> Errno { } // unset_env unsets a single environment variable -unset_env :: proc(key: string) -> Errno { +unset_env :: proc(key: string) -> Error { k := win32.utf8_to_wstring(key) if !win32.SetEnvironmentVariableW(k, nil) { return get_last_error() diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 7831aa3e6..54c456fb4 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -9,7 +9,7 @@ is_path_separator :: proc(c: byte) -> bool { return c == '/' || c == '\\' } -open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) { +open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Error) { if len(path) == 0 { return INVALID_HANDLE, General_Error.Not_Exist } @@ -58,14 +58,14 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn return INVALID_HANDLE, get_last_error() } -close :: proc(fd: Handle) -> Errno { +close :: proc(fd: Handle) -> Error { if !win32.CloseHandle(win32.HANDLE(fd)) { return get_last_error() } return nil } -flush :: proc(fd: Handle) -> (err: Errno) { +flush :: proc(fd: Handle) -> (err: Error) { if !win32.FlushFileBuffers(win32.HANDLE(fd)) { err = get_last_error() } @@ -74,7 +74,7 @@ flush :: proc(fd: Handle) -> (err: Errno) { -write :: proc(fd: Handle, data: []byte) -> (int, Errno) { +write :: proc(fd: Handle, data: []byte) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -97,7 +97,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { } @(private="file") -read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { +read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Error) { if len(b) == 0 { return 0, nil } @@ -147,7 +147,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { return } -read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Errno) { +read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Error) { if len(data) == 0 { return 0, nil } @@ -184,7 +184,7 @@ read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Errno) { return total_read, nil } -seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { w: u32 switch whence { case 0: w = win32.FILE_BEGIN @@ -206,9 +206,9 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { return i64(hi)<<32 + i64(dw_ptr), nil } -file_size :: proc(fd: Handle) -> (i64, Errno) { +file_size :: proc(fd: Handle) -> (i64, Error) { length: win32.LARGE_INTEGER - err: Errno + err: Error if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) { err = get_last_error() } @@ -220,7 +220,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { MAX_RW :: 1<<30 @(private) -pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { +pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) { buf := data if len(buf) > MAX_RW { buf = buf[:MAX_RW] @@ -236,7 +236,7 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { h := win32.HANDLE(fd) done: win32.DWORD - e: Errno + e: Error if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { e = get_last_error() done = 0 @@ -244,7 +244,7 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { return int(done), e } @(private) -pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { +pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) { buf := data if len(buf) > MAX_RW { buf = buf[:MAX_RW] @@ -258,7 +258,7 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { h := win32.HANDLE(fd) done: win32.DWORD - e: Errno + e: Error if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) { e = get_last_error() done = 0 @@ -276,7 +276,7 @@ on Windows, read_at changes the position of the file cursor, on *nix, it does no will read from the location twice on *nix, and from two different locations on Windows */ -read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { if offset < 0 { return 0, ERROR_NEGATIVE_OFFSET } @@ -308,7 +308,7 @@ on Windows, write_at changes the position of the file cursor, on *nix, it does n will write to the location twice on *nix, and to two different locations on Windows */ -write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { if offset < 0 { return 0, ERROR_NEGATIVE_OFFSET } @@ -386,7 +386,7 @@ get_current_directory :: proc(allocator := context.allocator) -> string { return win32.utf16_to_utf8(dir_buf_wstr, allocator) or_else "" } -set_current_directory :: proc(path: string) -> (err: Errno) { +set_current_directory :: proc(path: string) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wstr := win32.utf8_to_wstring(path, context.temp_allocator) @@ -402,7 +402,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { } change_directory :: set_current_directory -make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) { +make_directory :: proc(path: string, mode: u32 = 0) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() // Mode is unused on Windows, but is needed on *nix wpath := win32.utf8_to_wstring(path, context.temp_allocator) @@ -414,7 +414,7 @@ make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) { } -remove_directory :: proc(path: string) -> (err: Errno) { +remove_directory :: proc(path: string) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wpath := win32.utf8_to_wstring(path, context.temp_allocator) @@ -487,14 +487,14 @@ fix_long_path :: proc(path: string) -> string { } -link :: proc(old_name, new_name: string) -> (err: Errno) { +link :: proc(old_name, new_name: string) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() n := win32.utf8_to_wstring(fix_long_path(new_name)) o := win32.utf8_to_wstring(fix_long_path(old_name)) return Platform_Error(win32.CreateHardLinkW(n, o, nil)) } -unlink :: proc(path: string) -> (err: Errno) { +unlink :: proc(path: string) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wpath := win32.utf8_to_wstring(path, context.temp_allocator) @@ -506,7 +506,7 @@ unlink :: proc(path: string) -> (err: Errno) { -rename :: proc(old_path, new_path: string) -> (err: Errno) { +rename :: proc(old_path, new_path: string) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() from := win32.utf8_to_wstring(old_path, context.temp_allocator) to := win32.utf8_to_wstring(new_path, context.temp_allocator) @@ -518,7 +518,7 @@ rename :: proc(old_path, new_path: string) -> (err: Errno) { } -ftruncate :: proc(fd: Handle, length: i64) -> (err: Errno) { +ftruncate :: proc(fd: Handle, length: i64) -> (err: Error) { curr_off := seek(fd, 0, 1) or_return defer seek(fd, curr_off, 0) _= seek(fd, length, 0) or_return @@ -529,14 +529,14 @@ ftruncate :: proc(fd: Handle, length: i64) -> (err: Errno) { return nil } -truncate :: proc(path: string, length: i64) -> (err: Errno) { +truncate :: proc(path: string, length: i64) -> (err: Error) { fd := open(path, O_WRONLY|O_CREATE, 0o666) or_return defer close(fd) return ftruncate(fd, length) } -remove :: proc(name: string) -> Errno { +remove :: proc(name: string) -> Error { p := win32.utf8_to_wstring(fix_long_path(name)) err, err1: win32.DWORD if !win32.DeleteFileW(p) { @@ -574,7 +574,7 @@ remove :: proc(name: string) -> Errno { } -pipe :: proc() -> (r, w: Handle, err: Errno) { +pipe :: proc() -> (r, w: Handle, err: Error) { sa: win32.SECURITY_ATTRIBUTES sa.nLength = size_of(win32.SECURITY_ATTRIBUTES) sa.bInheritHandle = true diff --git a/core/os/os.odin b/core/os/os.odin index 3db3c5bd7..e383b779d 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -64,15 +64,15 @@ is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { return i32(v), i32(v) != 0 } -write_string :: proc(fd: Handle, str: string) -> (int, Errno) { +write_string :: proc(fd: Handle, str: string) -> (int, Error) { return write(fd, transmute([]byte)str) } -write_byte :: proc(fd: Handle, b: byte) -> (int, Errno) { +write_byte :: proc(fd: Handle, b: byte) -> (int, Error) { return write(fd, []byte{b}) } -write_rune :: proc(fd: Handle, r: rune) -> (int, Errno) { +write_rune :: proc(fd: Handle, r: rune) -> (int, Error) { if r < utf8.RUNE_SELF { return write_byte(fd, byte(r)) } @@ -120,7 +120,7 @@ write_encoded_rune :: proc(f: Handle, r: rune) -> (n: int, err: Error) { return } -read_at_least :: proc(fd: Handle, buf: []byte, min: int) -> (n: int, err: Errno) { +read_at_least :: proc(fd: Handle, buf: []byte, min: int) -> (n: int, err: Error) { if len(buf) < min { return 0, io.Error.Short_Buffer } @@ -135,7 +135,7 @@ read_at_least :: proc(fd: Handle, buf: []byte, min: int) -> (n: int, err: Errno) return } -read_full :: proc(fd: Handle, buf: []byte) -> (n: int, err: Errno) { +read_full :: proc(fd: Handle, buf: []byte) -> (n: int, err: Error) { return read_at_least(fd, buf, len(buf)) } @@ -170,7 +170,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator, context.allocator = allocator length: i64 - err: Errno + err: Error if length, err = file_size(fd); err != nil { return nil, false } @@ -219,11 +219,11 @@ write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (succ return write_err == nil } -write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) { +write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Error) { return write(fd, ([^]byte)(data)[:len]) } -read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) { +read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Error) { return read(fd, ([^]byte)(data)[:len]) } diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin index d7234ce8b..e4191d9aa 100644 --- a/core/os/os2/errors_linux.odin +++ b/core/os/os2/errors_linux.odin @@ -4,7 +4,7 @@ package os2 import "core:sys/linux" @(rodata) -_errno_strings : [linux.Errno]string = { +_errno_strings : [linux.Error]string = { .NONE = "Success", .EPERM = "Operation not permitted", .ENOENT = "No such file or directory", @@ -142,7 +142,7 @@ _errno_strings : [linux.Errno]string = { } -_get_platform_error :: proc(errno: linux.Errno) -> Error { +_get_platform_error :: proc(errno: linux.Error) -> Error { #partial switch errno { case .NONE: return nil @@ -158,8 +158,8 @@ _get_platform_error :: proc(errno: linux.Errno) -> Error { } _error_string :: proc(errno: i32) -> string { - if errno >= 0 && errno <= i32(max(linux.Errno)) { - return _errno_strings[linux.Errno(errno)] + if errno >= 0 && errno <= i32(max(linux.Error)) { + return _errno_strings[linux.Error(errno)] } return "Unknown Error" } diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index be60f9b86..62386675d 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -59,7 +59,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { path_bytes[len(path)] = 0 dfd: linux.Fd - errno: linux.Errno + errno: linux.Error if path_bytes[0] == '/' { dfd, errno = linux.open("/", _OPENDIR_FLAGS) path_bytes = path_bytes[1:] diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index a1478e99d..ee2a5aa04 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -13,7 +13,7 @@ File_Time :: distinct u64 INVALID_HANDLE :: ~Handle(0) -_Platform_Error :: enum i32 { +_Platform_Error :: enum i32 { NONE = 0, EPERM = 1, /* Operation not permitted */ ENOENT = 2, /* No such file or directory */ @@ -149,7 +149,7 @@ _Platform_Error :: enum i32 { EOWNERDEAD = 105, /* Previous owner died */ EQFUL = 106, /* Interface output queue is full */ - ELAS = 106, /* Must be equal largest errno */ + ELAS = 106, /* Must be equal largest Error */ } @@ -644,7 +644,7 @@ get_last_error_string :: proc() -> string { } -open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (handle: Handle, err: Errno) { +open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (handle: Handle, err: Error) { isDir := is_dir_path(path) flags := flags if isDir { @@ -678,11 +678,11 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (handle: Handl return } -fchmod :: proc(fd: Handle, mode: u16) -> Errno { +fchmod :: proc(fd: Handle, mode: u16) -> Error { return cast(Platform_Error)_unix_fchmod(fd, mode) } -close :: proc(fd: Handle) -> Errno { +close :: proc(fd: Handle) -> Error { return cast(Platform_Error)_unix_close(fd) } @@ -696,7 +696,7 @@ close :: proc(fd: Handle) -> Errno { @(private) MAX_RW :: 1 << 30 -write :: proc(fd: Handle, data: []byte) -> (int, Errno) { +write :: proc(fd: Handle, data: []byte) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -705,12 +705,12 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { bytes_written := _unix_write(fd, raw_data(data), to_write) if bytes_written < 0 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return bytes_written, nil } -read :: proc(fd: Handle, data: []u8) -> (int, Errno) { +read :: proc(fd: Handle, data: []u8) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -719,12 +719,12 @@ read :: proc(fd: Handle, data: []u8) -> (int, Errno) { bytes_read := _unix_read(fd, raw_data(data), to_read) if bytes_read < 0 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return bytes_read, nil } -read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -733,12 +733,12 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { bytes_read := _unix_pread(fd, raw_data(data), to_read, offset) if bytes_read < 0 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return bytes_read, nil } -write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -747,12 +747,12 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { bytes_written := _unix_pwrite(fd, raw_data(data), to_write, offset) if bytes_written < 0 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return bytes_written, nil } -seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { assert(fd != -1) final_offset := i64(_unix_lseek(fd, int(offset), c.int(whence))) @@ -762,7 +762,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { return final_offset, nil } -file_size :: proc(fd: Handle) -> (i64, Errno) { +file_size :: proc(fd: Handle) -> (i64, Error) { prev, _ := seek(fd, 0, SEEK_CUR) size, err := seek(fd, 0, SEEK_END) seek(fd, prev, SEEK_SET) @@ -776,13 +776,13 @@ stdin: Handle = 0 // get_std_handle(win32.STD_INPUT_HANDLE); stdout: Handle = 1 // get_std_handle(win32.STD_OUTPUT_HANDLE); stderr: Handle = 2 // get_std_handle(win32.STD_ERROR_HANDLE); -last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Errno) { +last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Error) { s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } -last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Errno) { +last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil @@ -803,7 +803,7 @@ is_file_handle :: proc(fd: Handle) -> bool { is_file_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat - err: Errno + err: Error if follow_links { s, err = _stat(path) } else { @@ -826,7 +826,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat - err: Errno + err: Error if follow_links { s, err = _stat(path) } else { @@ -855,66 +855,66 @@ rename :: proc(old: string, new: string) -> bool { return _unix_rename(old_cstr, new_cstr) != -1 } -remove :: proc(path: string) -> Errno { +remove :: proc(path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_remove(path_cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @private -_stat :: proc(path: string) -> (OS_Stat, Errno) { +_stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) s: OS_Stat result := _unix_stat(cstr, &s) if result == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_lstat :: proc(path: string) -> (OS_Stat, Errno) { +_lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) s: OS_Stat result := _unix_lstat(cstr, &s) if result == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { +_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat result := _unix_fstat(fd, &s) if result == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_fdopendir :: proc(fd: Handle) -> (Dir, Errno) { +_fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Errno(get_last_error()) + return nil, Error(get_last_error()) } return dirp, nil } @private -_closedir :: proc(dirp: Dir) -> Errno { +_closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -925,12 +925,12 @@ _rewinddir :: proc(dirp: Dir) { } @private -_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) { +_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Errno(get_last_error()) + err = Error(get_last_error()) return } @@ -944,7 +944,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) } @private -_readlink :: proc(path: string) -> (string, Errno) { +_readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -954,7 +954,7 @@ _readlink :: proc(path: string) -> (string, Errno) { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) if rc == -1 { delete(buf) - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } else if rc == int(bufsz) { // NOTE(laleksic, 2021-01-21): Any cleaner way to resize the slice? bufsz *= 2 @@ -966,13 +966,13 @@ _readlink :: proc(path: string) -> (string, Errno) { } } -absolute_path_from_handle :: proc(fd: Handle) -> (path: string, err: Errno) { +absolute_path_from_handle :: proc(fd: Handle) -> (path: string, err: Error) { buf: [DARWIN_MAXPATHLEN]byte _ = fcntl(int(fd), F_GETPATH, int(uintptr(&buf[0]))) or_return return strings.clone_from_cstring(cstring(&buf[0])) } -absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { +absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { rel = "." @@ -983,7 +983,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } defer _unix_free(path_ptr) @@ -999,7 +999,7 @@ access :: proc(path: string, mask: int) -> bool { return _unix_access(cstr, c.int(mask)) == 0 } -flush :: proc(fd: Handle) -> Errno { +flush :: proc(fd: Handle) -> Error { return cast(Platform_Error)_unix_fsync(fd) } @@ -1018,23 +1018,23 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string) return } -set_env :: proc(key, value: string) -> Errno { +set_env :: proc(key, value: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() key_cstring := strings.clone_to_cstring(key, context.temp_allocator) value_cstring := strings.clone_to_cstring(value, context.temp_allocator) res := _unix_setenv(key_cstring, value_cstring, 1) if res < 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -unset_env :: proc(key: string) -> Errno { +unset_env :: proc(key: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() s := strings.clone_to_cstring(key, context.temp_allocator) res := _unix_unsetenv(s) if res < 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -1047,7 +1047,7 @@ get_current_directory :: proc() -> string { if cwd != nil { return string(cwd) } - if Errno(get_last_error()) != ERANGE { + if Error(get_last_error()) != ERANGE { delete(buf) return "" } @@ -1056,22 +1056,22 @@ get_current_directory :: proc() -> string { unreachable() } -set_current_directory :: proc(path: string) -> (err: Errno) { +set_current_directory :: proc(path: string) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -make_directory :: proc(path: string, mode: u16 = 0o775) -> Errno { +make_directory :: proc(path: string, mode: u16 = 0o775) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -1145,106 +1145,106 @@ _alloc_command_line_arguments :: proc() -> []string { return res } -socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Errno) { +socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { result := _unix_socket(domain, type, protocol) if result < 0 { - return 0, Errno(get_last_error()) + return 0, Error(get_last_error()) } return Socket(result), nil } -connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { +connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { result := _unix_connect(int(sd), addr, len) if result < 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { +bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { result := _unix_bind(int(sd), addr, len) if result < 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Errno) { +accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Error) { result := _unix_accept(int(sd), rawptr(addr), len) if result < 0 { - return 0, Errno(get_last_error()) + return 0, Error(get_last_error()) } return Socket(result), nil } -listen :: proc(sd: Socket, backlog: int) -> (Errno) { +listen :: proc(sd: Socket, backlog: int) -> (Error) { result := _unix_listen(int(sd), backlog) if result < 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> (Errno) { +setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> (Error) { result := _unix_setsockopt(int(sd), level, optname, optval, optlen) if result < 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Errno { +getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Error { result := _unix_getsockopt(int(sd), level, optname, optval, optlen) if result < 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Errno) { +recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Error) { result := _unix_recvfrom(int(sd), raw_data(data), len(data), flags, addr, addr_size) if result < 0 { - return 0, Errno(get_last_error()) + return 0, Error(get_last_error()) } return u32(result), nil } -recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { +recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { result := _unix_recv(int(sd), raw_data(data), len(data), flags) if result < 0 { - return 0, Errno(get_last_error()) + return 0, Error(get_last_error()) } return u32(result), nil } -sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: socklen_t) -> (u32, Errno) { +sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: socklen_t) -> (u32, Error) { result := _unix_sendto(int(sd), raw_data(data), len(data), flags, addr, addrlen) if result < 0 { - return 0, Errno(get_last_error()) + return 0, Error(get_last_error()) } return u32(result), nil } -send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { +send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { result := _unix_send(int(sd), raw_data(data), len(data), 0) if result < 0 { - return 0, Errno(get_last_error()) + return 0, Error(get_last_error()) } return u32(result), nil } -shutdown :: proc(sd: Socket, how: int) -> (Errno) { +shutdown :: proc(sd: Socket, how: int) -> (Error) { result := _unix_shutdown(int(sd), how) if result < 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { +fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Error) { result := _unix__fcntl(Handle(fd), c.int(cmd), uintptr(arg)) if result < 0 { - return 0, Errno(get_last_error()) + return 0, Error(get_last_error()) } return int(result), nil } diff --git a/core/os/os_essence.odin b/core/os/os_essence.odin index 7509785bc..71708cfbb 100644 --- a/core/os/os_essence.odin +++ b/core/os/os_essence.odin @@ -5,7 +5,7 @@ import "core:sys/es" Handle :: distinct int _Platform_Error :: enum i32 {NONE} -// ERROR_NONE :: Errno(es.SUCCESS) +// ERROR_NONE :: Error(es.SUCCESS) O_RDONLY :: 0x1 O_WRONLY :: 0x2 @@ -30,26 +30,26 @@ heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { return es.HeapReallocate(ptr, new_size, false) } -open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { - return (Handle) (0), (Errno) (1) +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Error) { + return (Handle) (0), (Error) (1) } -close :: proc(fd: Handle) -> Errno { - return (Errno) (1) +close :: proc(fd: Handle) -> Error { + return (Error) (1) } -file_size :: proc(fd: Handle) -> (i64, Errno) { - return (i64) (0), (Errno) (1) +file_size :: proc(fd: Handle) -> (i64, Error) { + return (i64) (0), (Error) (1) } -read :: proc(fd: Handle, data: []byte) -> (int, Errno) { - return (int) (0), (Errno) (1) +read :: proc(fd: Handle, data: []byte) -> (int, Error) { + return (int) (0), (Error) (1) } -write :: proc(fd: Handle, data: []u8) -> (int, Errno) { - return (int) (0), (Errno) (1) +write :: proc(fd: Handle, data: []u8) -> (int, Error) { + return (int) (0), (Error) (1) } -seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { - return (i64) (0), (Errno) (1) +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { + return (i64) (0), (Error) (1) } diff --git a/core/os/os_js.odin b/core/os/os_js.odin index f27b13097..e14742900 100644 --- a/core/os/os_js.odin +++ b/core/os/os_js.odin @@ -7,38 +7,38 @@ is_path_separator :: proc(c: byte) -> bool { return c == '/' || c == '\\' } -open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) { +open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Error) { unimplemented("core:os procedure not supported on JS target") } -close :: proc(fd: Handle) -> Errno { +close :: proc(fd: Handle) -> Error { unimplemented("core:os procedure not supported on JS target") } -flush :: proc(fd: Handle) -> (err: Errno) { +flush :: proc(fd: Handle) -> (err: Error) { unimplemented("core:os procedure not supported on JS target") } -write :: proc(fd: Handle, data: []byte) -> (int, Errno) { +write :: proc(fd: Handle, data: []byte) -> (int, Error) { unimplemented("core:os procedure not supported on JS target") } @(private="file") -read_console :: proc(handle: Handle, b: []byte) -> (n: int, err: Errno) { +read_console :: proc(handle: Handle, b: []byte) -> (n: int, err: Error) { unimplemented("core:os procedure not supported on JS target") } -read :: proc(fd: Handle, data: []byte) -> (int, Errno) { +read :: proc(fd: Handle, data: []byte) -> (int, Error) { unimplemented("core:os procedure not supported on JS target") } -seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { unimplemented("core:os procedure not supported on JS target") } -file_size :: proc(fd: Handle) -> (i64, Errno) { +file_size :: proc(fd: Handle) -> (i64, Error) { unimplemented("core:os procedure not supported on JS target") } @@ -47,18 +47,18 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { MAX_RW :: 1<<30 @(private) -pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { +pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) { unimplemented("core:os procedure not supported on JS target") } @(private) -pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { +pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) { unimplemented("core:os procedure not supported on JS target") } -read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { unimplemented("core:os procedure not supported on JS target") } -write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { unimplemented("core:os procedure not supported on JS target") } @@ -90,22 +90,22 @@ get_current_directory :: proc(allocator := context.allocator) -> string { unimplemented("core:os procedure not supported on JS target") } -set_current_directory :: proc(path: string) -> (err: Errno) { +set_current_directory :: proc(path: string) -> (err: Error) { unimplemented("core:os procedure not supported on JS target") } -change_directory :: proc(path: string) -> (err: Errno) { +change_directory :: proc(path: string) -> (err: Error) { unimplemented("core:os procedure not supported on JS target") } -make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) { +make_directory :: proc(path: string, mode: u32 = 0) -> (err: Error) { unimplemented("core:os procedure not supported on JS target") } -remove_directory :: proc(path: string) -> (err: Errno) { +remove_directory :: proc(path: string) -> (err: Error) { unimplemented("core:os procedure not supported on JS target") } @@ -122,40 +122,40 @@ fix_long_path :: proc(path: string) -> string { } -link :: proc(old_name, new_name: string) -> (err: Errno) { +link :: proc(old_name, new_name: string) -> (err: Error) { unimplemented("core:os procedure not supported on JS target") } -unlink :: proc(path: string) -> (err: Errno) { +unlink :: proc(path: string) -> (err: Error) { unimplemented("core:os procedure not supported on JS target") } -rename :: proc(old_path, new_path: string) -> (err: Errno) { +rename :: proc(old_path, new_path: string) -> (err: Error) { unimplemented("core:os procedure not supported on JS target") } -ftruncate :: proc(fd: Handle, length: i64) -> (err: Errno) { +ftruncate :: proc(fd: Handle, length: i64) -> (err: Error) { unimplemented("core:os procedure not supported on JS target") } -truncate :: proc(path: string, length: i64) -> (err: Errno) { +truncate :: proc(path: string, length: i64) -> (err: Error) { unimplemented("core:os procedure not supported on JS target") } -remove :: proc(name: string) -> Errno { +remove :: proc(name: string) -> Error { unimplemented("core:os procedure not supported on JS target") } -pipe :: proc() -> (r, w: Handle, err: Errno) { +pipe :: proc() -> (r, w: Handle, err: Error) { unimplemented("core:os procedure not supported on JS target") } -read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { +read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Error) { unimplemented("core:os procedure not supported on JS target") } @@ -253,11 +253,11 @@ args := _alloc_command_line_arguments() -last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { +last_write_time :: proc(fd: Handle) -> (File_Time, Error) { unimplemented("core:os procedure not supported on JS target") } -last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { +last_write_time_by_name :: proc(name: string) -> (File_Time, Error) { unimplemented("core:os procedure not supported on JS target") } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 4d5b13930..985070eb2 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -512,7 +512,7 @@ is_path_separator :: proc(r: rune) -> bool { // determine errno from syscall return value @private -_get_errno :: proc(res: int) -> Errno { +_get_errno :: proc(res: int) -> Error { if res < 0 && res > -4096 { return Platform_Error(-res) } @@ -535,7 +535,7 @@ get_last_error :: proc "contextless" () -> Error { return err } -personality :: proc(persona: u64) -> (Errno) { +personality :: proc(persona: u64) -> (Error) { res := unix.sys_personality(persona) if res == -1 { return _get_errno(res) @@ -543,7 +543,7 @@ personality :: proc(persona: u64) -> (Errno) { return nil } -fork :: proc() -> (Pid, Errno) { +fork :: proc() -> (Pid, Error) { pid := unix.sys_fork() if pid == -1 { return -1, _get_errno(pid) @@ -551,7 +551,7 @@ fork :: proc() -> (Pid, Errno) { return Pid(pid), nil } -execvp :: proc(path: string, args: []string) -> Errno { +execvp :: proc(path: string, args: []string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -562,11 +562,11 @@ execvp :: proc(path: string, args: []string) -> Errno { } _unix_execvp(path_cstr, raw_data(args_cstrs)) - return Errno(get_last_error()) + return Error(get_last_error()) } -open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0o000) -> (Handle, Errno) { +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0o000) -> (Handle, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := unix.sys_open(cstr, flags, uint(mode)) @@ -576,7 +576,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0o000) -> (Handle, return Handle(handle), nil } -close :: proc(fd: Handle) -> Errno { +close :: proc(fd: Handle) -> Error { return _get_errno(unix.sys_close(int(fd))) } @@ -589,7 +589,7 @@ close :: proc(fd: Handle) -> Errno { @(private) MAX_RW :: 1 << 30 -read :: proc(fd: Handle, data: []byte) -> (int, Errno) { +read :: proc(fd: Handle, data: []byte) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -603,7 +603,7 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) { return bytes_read, nil } -write :: proc(fd: Handle, data: []byte) -> (int, Errno) { +write :: proc(fd: Handle, data: []byte) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -617,7 +617,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { return bytes_written, nil } -read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -631,7 +631,7 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { return bytes_read, nil } -write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -645,7 +645,7 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { return bytes_written, nil } -seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := unix.sys_lseek(int(fd), offset, whence) if res < 0 { return -1, _get_errno(int(res)) @@ -653,7 +653,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { return i64(res), nil } -file_size :: proc(fd: Handle) -> (i64, Errno) { +file_size :: proc(fd: Handle) -> (i64, Error) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- result := unix.sys_fstat(int(fd), rawptr(&s)) @@ -663,26 +663,26 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { return max(s.size, 0), nil } -rename :: proc(old_path, new_path: string) -> Errno { +rename :: proc(old_path, new_path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) return _get_errno(unix.sys_rename(old_path_cstr, new_path_cstr)) } -remove :: proc(path: string) -> Errno { +remove :: proc(path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) return _get_errno(unix.sys_unlink(path_cstr)) } -make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno { +make_directory :: proc(path: string, mode: u32 = 0o775) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) return _get_errno(unix.sys_mkdir(path_cstr, uint(mode))) } -remove_directory :: proc(path: string) -> Errno { +remove_directory :: proc(path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) return _get_errno(unix.sys_rmdir(path_cstr)) @@ -698,7 +698,7 @@ is_file_handle :: proc(fd: Handle) -> bool { is_file_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat - err: Errno + err: Error if follow_links { s, err = _stat(path) } else { @@ -721,7 +721,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat - err: Errno + err: Error if follow_links { s, err = _stat(path) } else { @@ -753,20 +753,20 @@ stderr: Handle = 2 last_write_time :: proc(fd: Handle) -> File_Time {} last_write_time_by_name :: proc(name: string) -> File_Time {} */ -last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Errno) { +last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Error) { s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } -last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Errno) { +last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } @private -_stat :: proc(path: string) -> (OS_Stat, Errno) { +_stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -780,7 +780,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { } @private -_lstat :: proc(path: string) -> (OS_Stat, Errno) { +_lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -794,7 +794,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { } @private -_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { +_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- result := unix.sys_fstat(int(fd), rawptr(&s)) @@ -805,19 +805,19 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { } @private -_fdopendir :: proc(fd: Handle) -> (Dir, Errno) { +_fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Errno(get_last_error()) + return nil, Error(get_last_error()) } return dirp, nil } @private -_closedir :: proc(dirp: Dir) -> Errno { +_closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -828,12 +828,12 @@ _rewinddir :: proc(dirp: Dir) { } @private -_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) { +_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Errno(get_last_error()) + err = Error(get_last_error()) return } err = nil @@ -848,7 +848,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) } @private -_readlink :: proc(path: string) -> (string, Errno) { +_readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -870,7 +870,7 @@ _readlink :: proc(path: string) -> (string, Errno) { } } -absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { +absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { buf : [256]byte fd_str := strconv.itoa( buf[:], cast(int)fd ) @@ -880,7 +880,7 @@ absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { return _readlink(procfs_path) } -absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { +absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { rel = "." @@ -891,7 +891,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } defer _unix_free(path_ptr) @@ -900,7 +900,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { return path, nil } -access :: proc(path: string, mask: int) -> (bool, Errno) { +access :: proc(path: string, mask: int) -> (bool, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) result := unix.sys_access(cstr, mask) @@ -926,24 +926,24 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string) return } -set_env :: proc(key, value: string) -> Errno { +set_env :: proc(key, value: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() key_cstring := strings.clone_to_cstring(key, context.temp_allocator) value_cstring := strings.clone_to_cstring(value, context.temp_allocator) // NOTE(GoNZooo): `setenv` instead of `putenv` because it copies both key and value more commonly res := _unix_setenv(key_cstring, value_cstring, 1) if res < 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -unset_env :: proc(key: string) -> Errno { +unset_env :: proc(key: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() s := strings.clone_to_cstring(key, context.temp_allocator) res := _unix_putenv(s) if res < 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -969,7 +969,7 @@ get_current_directory :: proc() -> string { unreachable() } -set_current_directory :: proc(path: string) -> (err: Errno) { +set_current_directory :: proc(path: string) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := unix.sys_chdir(cstr) @@ -1034,7 +1034,7 @@ _alloc_command_line_arguments :: proc() -> []string { return res } -socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Errno) { +socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { result := unix.sys_socket(domain, type, protocol) if result < 0 { return 0, _get_errno(result) @@ -1042,7 +1042,7 @@ socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Errno) { return Socket(result), nil } -bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { +bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { result := unix.sys_bind(int(sd), addr, len) if result < 0 { return _get_errno(result) @@ -1051,7 +1051,7 @@ bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { } -connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { +connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { result := unix.sys_connect(int(sd), addr, len) if result < 0 { return _get_errno(result) @@ -1059,7 +1059,7 @@ connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Errno) { return nil } -accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Errno) { +accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Error) { result := unix.sys_accept(int(sd), rawptr(addr), len) if result < 0 { return 0, _get_errno(result) @@ -1067,7 +1067,7 @@ accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Errno) { return Socket(result), nil } -listen :: proc(sd: Socket, backlog: int) -> (Errno) { +listen :: proc(sd: Socket, backlog: int) -> (Error) { result := unix.sys_listen(int(sd), backlog) if result < 0 { return _get_errno(result) @@ -1075,7 +1075,7 @@ listen :: proc(sd: Socket, backlog: int) -> (Errno) { return nil } -setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> (Errno) { +setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> (Error) { result := unix.sys_setsockopt(int(sd), level, optname, optval, optlen) if result < 0 { return _get_errno(result) @@ -1084,7 +1084,7 @@ setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: } -recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Errno) { +recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Error) { result := unix.sys_recvfrom(int(sd), raw_data(data), len(data), flags, addr, uintptr(addr_size)) if result < 0 { return 0, _get_errno(int(result)) @@ -1092,7 +1092,7 @@ recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_siz return u32(result), nil } -recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { +recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { result := unix.sys_recvfrom(int(sd), raw_data(data), len(data), flags, nil, 0) if result < 0 { return 0, _get_errno(int(result)) @@ -1101,7 +1101,7 @@ recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { } -sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: socklen_t) -> (u32, Errno) { +sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: socklen_t) -> (u32, Error) { result := unix.sys_sendto(int(sd), raw_data(data), len(data), flags, addr, addrlen) if result < 0 { return 0, _get_errno(int(result)) @@ -1109,7 +1109,7 @@ sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: soc return u32(result), nil } -send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { +send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { result := unix.sys_sendto(int(sd), raw_data(data), len(data), 0, nil, 0) if result < 0 { return 0, _get_errno(int(result)) @@ -1117,7 +1117,7 @@ send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Errno) { return u32(result), nil } -shutdown :: proc(sd: Socket, how: int) -> (Errno) { +shutdown :: proc(sd: Socket, how: int) -> (Error) { result := unix.sys_shutdown(int(sd), how) if result < 0 { return _get_errno(result) @@ -1125,7 +1125,7 @@ shutdown :: proc(sd: Socket, how: int) -> (Errno) { return nil } -fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { +fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Error) { result := unix.sys_fcntl(fd, cmd, arg) if result < 0 { return 0, _get_errno(result) @@ -1133,7 +1133,7 @@ fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { return result, nil } -poll :: proc(fds: []pollfd, timeout: int) -> (int, Errno) { +poll :: proc(fds: []pollfd, timeout: int) -> (int, Error) { result := unix.sys_poll(raw_data(fds), uint(len(fds)), timeout) if result < 0 { return 0, _get_errno(result) @@ -1141,7 +1141,7 @@ poll :: proc(fds: []pollfd, timeout: int) -> (int, Errno) { return result, nil } -ppoll :: proc(fds: []pollfd, timeout: ^unix.timespec, sigmask: ^sigset_t) -> (int, Errno) { +ppoll :: proc(fds: []pollfd, timeout: ^unix.timespec, sigmask: ^sigset_t) -> (int, Error) { result := unix.sys_ppoll(raw_data(fds), uint(len(fds)), timeout, sigmask, size_of(sigset_t)) if result < 0 { return 0, _get_errno(result) diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 99c28d880..574431c4c 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -114,7 +114,7 @@ get_last_error :: proc "contextless" () -> Error { } -last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { +last_write_time :: proc(fd: Handle) -> (File_Time, Error) { file_info: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(win32.HANDLE(fd), &file_info) { return 0, get_last_error() @@ -124,7 +124,7 @@ last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { return lo | hi << 32, nil } -last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { +last_write_time_by_name :: proc(name: string) -> (File_Time, Error) { data: win32.WIN32_FILE_ATTRIBUTE_DATA wide_path := win32.utf8_to_wstring(name) diff --git a/core/os/stat_unix.odin b/core/os/stat_unix.odin index e123dca23..189f32743 100644 --- a/core/os/stat_unix.odin +++ b/core/os/stat_unix.odin @@ -100,7 +100,7 @@ path_base :: proc(path: string) -> string { } -lstat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, err: Errno) { +lstat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, err: Error) { context.allocator = allocator s := _lstat(name) or_return @@ -110,7 +110,7 @@ lstat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, e return } -stat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, err: Errno) { +stat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, err: Error) { context.allocator = allocator s := _stat(name) or_return @@ -120,7 +120,7 @@ stat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, er return } -fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err: Errno) { +fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err: Error) { context.allocator = allocator s := _fstat(fd) or_return diff --git a/core/os/stream.odin b/core/os/stream.odin index 48100a425..c421285cd 100644 --- a/core/os/stream.odin +++ b/core/os/stream.odin @@ -14,7 +14,7 @@ stream_from_handle :: proc(fd: Handle) -> io.Stream { _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { fd := Handle(uintptr(stream_data)) n_int: int - os_err: Errno + os_err: Error switch mode { case .Close: close(fd) From 1d75a612d54f102ef530c1f58546e3cdb239160c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:47:23 +0100 Subject: [PATCH 065/122] `os.Errno` -> `os.Error` --- core/flags/errors.odin | 2 +- core/flags/internal_rtti.odin | 2 +- core/path/filepath/path_windows.odin | 2 +- core/path/filepath/walk.odin | 10 +++++----- core/prof/spall/spall.odin | 2 +- core/prof/spall/spall_linux.odin | 4 ++-- core/prof/spall/spall_unix.odin | 4 ++-- core/prof/spall/spall_windows.odin | 2 +- src/check_expr.cpp | 1 + 9 files changed, 15 insertions(+), 14 deletions(-) diff --git a/core/flags/errors.odin b/core/flags/errors.odin index 21ea05477..6e48f6ccf 100644 --- a/core/flags/errors.odin +++ b/core/flags/errors.odin @@ -28,7 +28,7 @@ Parse_Error :: struct { // Provides more granular information than what just a string could hold. Open_File_Error :: struct { filename: string, - errno: os.Errno, + errno: os.Error, mode: int, perms: int, } diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin index ac39eaa8b..8838b771d 100644 --- a/core/flags/internal_rtti.odin +++ b/core/flags/internal_rtti.odin @@ -255,7 +255,7 @@ parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type: handle, errno := os.open(str, mode, perms) if errno != 0 { - // NOTE(Feoramund): os.Errno is system-dependent, and there's + // NOTE(Feoramund): os.Error is system-dependent, and there's // currently no good way to translate them all into strings. // // The upcoming `os2` package will hopefully solve this. diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin index ae26e1394..6a9ac9dee 100644 --- a/core/path/filepath/path_windows.odin +++ b/core/path/filepath/path_windows.odin @@ -52,7 +52,7 @@ is_abs :: proc(path: string) -> bool { @(private) -temp_full_path :: proc(name: string) -> (path: string, err: os.Errno) { +temp_full_path :: proc(name: string) -> (path: string, err: os.Error) { ta := context.temp_allocator name := name diff --git a/core/path/filepath/walk.odin b/core/path/filepath/walk.odin index 9ba3165dc..9fd4c455f 100644 --- a/core/path/filepath/walk.odin +++ b/core/path/filepath/walk.odin @@ -14,7 +14,7 @@ import "core:slice" // The sole exception is if 'skip_dir' is returned as true: // when 'skip_dir' is invoked on a directory. 'walk' skips directory contents // when 'skip_dir' is invoked on a non-directory. 'walk' skips the remaining files in the containing directory -Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Errno, user_data: rawptr) -> (err: os.Errno, skip_dir: bool) +Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Error, user_data: rawptr) -> (err: os.Error, skip_dir: bool) // walk walks the file tree rooted at 'root', calling 'walk_proc' for each file or directory in the tree, including 'root' // All errors that happen visiting files and directories are filtered by walk_proc @@ -22,7 +22,7 @@ Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Errno, user_data: rawptr) // NOTE: Walking large directories can be inefficient due to the lexical sort // NOTE: walk does not follow symbolic links // NOTE: os.File_Info uses the 'context.temp_allocator' to allocate, and will delete when it is done -walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Errno { +walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Error { info, err := os.lstat(root, context.temp_allocator) defer os.file_info_delete(info, context.temp_allocator) @@ -37,7 +37,7 @@ walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Errno @(private) -_walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (err: os.Errno, skip_dir: bool) { +_walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (err: os.Error, skip_dir: bool) { if !info.is_dir { if info.fullpath == "" && info.name == "" { // ignore empty things @@ -47,7 +47,7 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (e } fis: []os.File_Info - err1: os.Errno + err1: os.Error fis, err = read_dir(info.fullpath, context.temp_allocator) defer os.file_info_slice_delete(fis, context.temp_allocator) @@ -70,7 +70,7 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (e } @(private) -read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> ([]os.File_Info, os.Errno) { +read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> ([]os.File_Info, os.Error) { f, err := os.open(dir_name, os.O_RDONLY) if err != 0 { return nil, err diff --git a/core/prof/spall/spall.odin b/core/prof/spall/spall.odin index a6fc59e74..38c563248 100644 --- a/core/prof/spall/spall.odin +++ b/core/prof/spall/spall.odin @@ -227,7 +227,7 @@ _buffer_end :: proc "contextless" (ctx: ^Context, buffer: ^Buffer) #no_bounds_ch } @(no_instrumentation) -write :: proc "contextless" (fd: os.Handle, buf: []byte) -> (n: int, err: os.Errno) { +write :: proc "contextless" (fd: os.Handle, buf: []byte) -> (n: int, err: os.Error) { return _write(fd, buf) } diff --git a/core/prof/spall/spall_linux.odin b/core/prof/spall/spall_linux.odin index 3f475c5e0..deee15aa1 100644 --- a/core/prof/spall/spall_linux.odin +++ b/core/prof/spall/spall_linux.odin @@ -10,7 +10,7 @@ import "core:sys/linux" MAX_RW :: 0x7fffffff @(no_instrumentation) -_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Errno) #no_bounds_check /* bounds check would segfault instrumentation */ { +_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { if len(data) == 0 { return 0, os.ERROR_NONE } @@ -19,7 +19,7 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.E chunk := data[:min(len(data), MAX_RW)] written, errno := linux.write(linux.Fd(fd), chunk) if errno != .NONE { - return n, os.Errno(errno) + return n, os.Error(errno) } n += written } diff --git a/core/prof/spall/spall_unix.odin b/core/prof/spall/spall_unix.odin index e6ba7ecde..6da57ee95 100644 --- a/core/prof/spall/spall_unix.odin +++ b/core/prof/spall/spall_unix.odin @@ -30,7 +30,7 @@ get_last_error :: proc "contextless" () -> os.Platform_Error { MAX_RW :: 0x7fffffff @(no_instrumentation) -_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Errno) #no_bounds_check /* bounds check would segfault instrumentation */ { +_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { if len(data) == 0 { return 0, os.ERROR_NONE } @@ -39,7 +39,7 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.E chunk := data[:min(len(data), MAX_RW)] written := _unix_write(fd, raw_data(chunk), len(chunk)) if written < 0 { - return n, os.Errno(get_last_error()) + return n, os.Error(get_last_error()) } n += written } diff --git a/core/prof/spall/spall_windows.odin b/core/prof/spall/spall_windows.odin index a55c42852..105a61891 100644 --- a/core/prof/spall/spall_windows.odin +++ b/core/prof/spall/spall_windows.odin @@ -10,7 +10,7 @@ import win32 "core:sys/windows" MAX_RW :: 1<<30 @(no_instrumentation) -_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (int, os.Errno) #no_bounds_check /* bounds check would segfault instrumentation */ { +_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (int, os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { if len(data) == 0 { return 0, os.ERROR_NONE } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9df3c7076..9efd16af4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4463,6 +4463,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar // as a kind of transition period if (operand->mode == Addressing_Constant && target_type->kind == Type_Named && + (c->pkg == nullptr || c->pkg->name != "os") && target_type->Named.name == "Error") { Entity *e = target_type->Named.type_name; if (e->pkg && e->pkg->name == "os") { From 97c499dbb40deeef3778c9a20aa2b38d96aa46f1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:58:04 +0100 Subject: [PATCH 066/122] Begin mapping `os.Error` in the rest of the codebase --- core/flags/internal_rtti.odin | 2 +- core/net/socket_darwin.odin | 18 +-- core/os/os_darwin.odin | 1 + core/os/os_freebsd.odin | 99 ++++++++-------- core/os/os_haiku.odin | 69 +++++------ core/os/os_linux.odin | 1 + core/os/os_netbsd.odin | 109 +++++++++--------- core/os/os_openbsd.odin | 100 ++++++++-------- core/os/os_windows.odin | 4 + core/path/filepath/path_windows.odin | 6 +- core/prof/spall/spall.odin | 2 +- core/prof/spall/spall_linux.odin | 8 +- core/prof/spall/spall_unix.odin | 11 +- core/prof/spall/spall_windows.odin | 7 +- core/testing/runner.odin | 4 +- tests/core/flags/test_core_flags.odin | 2 +- tests/core/os/os.odin | 8 +- tests/documentation/documentation_tester.odin | 2 +- 18 files changed, 231 insertions(+), 222 deletions(-) diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin index 8838b771d..4c1db5d0b 100644 --- a/core/flags/internal_rtti.odin +++ b/core/flags/internal_rtti.odin @@ -254,7 +254,7 @@ parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type: } handle, errno := os.open(str, mode, perms) - if errno != 0 { + if errno != nil { // NOTE(Feoramund): os.Error is system-dependent, and there's // currently no good way to translate them all into strings. // diff --git a/core/net/socket_darwin.odin b/core/net/socket_darwin.odin index fc422b3a9..1cee33d1d 100644 --- a/core/net/socket_darwin.odin +++ b/core/net/socket_darwin.odin @@ -53,9 +53,9 @@ _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (so unreachable() } - sock, ok := os.socket(c_family, c_type, c_protocol) - if ok != os.ERROR_NONE { - err = Create_Socket_Error(ok) + sock, sock_err := os.socket(c_family, c_type, c_protocol) + if sock_err != nil { + err = Create_Socket_Error(os.is_platform_error(sock_err) or_else -1) return } @@ -84,7 +84,7 @@ _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_optio sockaddr := _endpoint_to_sockaddr(endpoint) res := os.connect(os.Socket(skt), (^os.SOCKADDR)(&sockaddr), i32(sockaddr.len)) - if res != os.ERROR_NONE { + if res != nil { err = Dial_Error(res) return } @@ -100,7 +100,7 @@ _bind :: proc(skt: Any_Socket, ep: Endpoint) -> (err: Network_Error) { sockaddr := _endpoint_to_sockaddr(ep) s := any_socket_to_socket(skt) res := os.bind(os.Socket(s), (^os.SOCKADDR)(&sockaddr), i32(sockaddr.len)) - if res != os.ERROR_NONE { + if res != nil { if res == os.EACCES && ep.port <= MAX_PRIVILEGED_PORT { err = .Privileged_Port_Without_Root } else { @@ -128,7 +128,7 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (skt: TCP_ bind(sock, interface_endpoint) or_return res := os.listen(os.Socket(skt), backlog) - if res != os.ERROR_NONE { + if res != nil { err = Listen_Error(res) return } @@ -141,9 +141,9 @@ _accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client sockaddr: os.SOCKADDR_STORAGE_LH sockaddrlen := c.int(size_of(sockaddr)) - client_sock, ok := os.accept(os.Socket(sock), cast(^os.SOCKADDR) &sockaddr, &sockaddrlen) - if ok != os.ERROR_NONE { - err = Accept_Error(ok) + client_sock, client_sock_err := os.accept(os.Socket(sock), cast(^os.SOCKADDR) &sockaddr, &sockaddrlen) + if client_sock_err != nil { + err = Accept_Error(os.is_platform_error(client_sock_err) or_else -1) return } client = TCP_Socket(client_sock) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index ee2a5aa04..d40044f7e 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -635,6 +635,7 @@ foreign dl { @(link_name="dlerror") _unix_dlerror :: proc() -> cstring --- } +@(require_results, no_instrumentation) get_last_error :: proc "contextless" () -> Error { return Platform_Error(__error()^) } diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index c64e5147f..3f65e393b 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -369,7 +369,7 @@ R_OK :: 4 // Test for read permission F_KINFO :: 22 foreign libc { - @(link_name="__error") __errno_location :: proc() -> ^c.int --- + @(link_name="__error") __Error_location :: proc() -> ^c.int --- @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- @@ -419,24 +419,25 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } +@(require_results, no_instrumentation) get_last_error :: proc "contextless" () -> Error { - return Platform_Error(__errno_location()^) + return Platform_Error(__Error_location()^) } -open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { - return INVALID_HANDLE, Errno(get_last_error()) + return INVALID_HANDLE, Error(get_last_error()) } return handle, nil } -close :: proc(fd: Handle) -> Errno { +close :: proc(fd: Handle) -> Error { result := _unix_close(fd) if result == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -449,16 +450,16 @@ close :: proc(fd: Handle) -> Errno { @(private) MAX_RW :: 1 << 30 -read :: proc(fd: Handle, data: []byte) -> (int, Errno) { +read :: proc(fd: Handle, data: []byte) -> (int, Error) { to_read := min(c.size_t(len(data)), MAX_RW) bytes_read := _unix_read(fd, &data[0], to_read) if bytes_read == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return int(bytes_read), nil } -write :: proc(fd: Handle, data: []byte) -> (int, Errno) { +write :: proc(fd: Handle, data: []byte) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -466,63 +467,63 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { to_write := min(c.size_t(len(data)), MAX_RW) bytes_written := _unix_write(fd, &data[0], to_write) if bytes_written == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return int(bytes_written), nil } -seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return res, nil } -file_size :: proc(fd: Handle) -> (size: i64, err: Errno) { +file_size :: proc(fd: Handle) -> (size: i64, err: Error) { size = -1 s := _fstat(fd) or_return size = s.size return } -rename :: proc(old_path, new_path: string) -> Errno { +rename :: proc(old_path, new_path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) res := _unix_rename(old_path_cstr, new_path_cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -remove :: proc(path: string) -> Errno { +remove :: proc(path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_unlink(path_cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { +make_directory :: proc(path: string, mode: mode_t = 0o775) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -remove_directory :: proc(path: string) -> Errno { +remove_directory :: proc(path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_rmdir(path_cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -537,7 +538,7 @@ is_file_handle :: proc(fd: Handle) -> bool { is_file_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat - err: Errno + err: Error if follow_links { s, err = _stat(path) } else { @@ -559,7 +560,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat - err: Errno + err: Error if follow_links { s, err = _stat(path) } else { @@ -584,7 +585,7 @@ stderr: Handle = 2 last_write_time :: proc(fd: Handle) -> File_Time {} last_write_time_by_name :: proc(name: string) -> File_Time {} */ -last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { +last_write_time :: proc(fd: Handle) -> (File_Time, Error) { s, err := _fstat(fd) if err != nil { return 0, err @@ -593,7 +594,7 @@ last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { return File_Time(modified), nil } -last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { +last_write_time_by_name :: proc(name: string) -> (File_Time, Error) { s, err := _stat(name) if err != nil { return 0, err @@ -603,19 +604,19 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { } @private -_stat :: proc(path: string) -> (OS_Stat, Errno) { +_stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) s: OS_Stat = --- result := _unix_lstat(cstr, &s) if result == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_lstat :: proc(path: string) -> (OS_Stat, Errno) { +_lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -623,35 +624,35 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { s: OS_Stat = --- res := _unix_lstat(cstr, &s) if res == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { +_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat = --- result := _unix_fstat(fd, &s) if result == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_fdopendir :: proc(fd: Handle) -> (Dir, Errno) { +_fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Errno(get_last_error()) + return nil, Error(get_last_error()) } return dirp, nil } @private -_closedir :: proc(dirp: Dir) -> Errno { +_closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -662,12 +663,12 @@ _rewinddir :: proc(dirp: Dir) { } @private -_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) { +_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Errno(get_last_error()) + err = Error(get_last_error()) return } @@ -680,7 +681,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) } @private -_readlink :: proc(path: string) -> (string, Errno) { +_readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -691,7 +692,7 @@ _readlink :: proc(path: string) -> (string, Errno) { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) if rc == -1 { delete(buf) - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } else if rc == int(bufsz) { bufsz += MAX_PATH delete(buf) @@ -701,10 +702,10 @@ _readlink :: proc(path: string) -> (string, Errno) { } } - return "", Errno{} + return "", Error{} } -absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { +absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { // NOTE(Feoramund): The situation isn't ideal, but this was the best way I // could find to implement this. There are a couple outstanding bug reports // regarding the desire to retrieve an absolute path from a handle, but to @@ -719,14 +720,14 @@ absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { res := _unix_fcntl(fd, F_KINFO, cast(uintptr)&kinfo) if res == -1 { - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } path := strings.clone_from_cstring_bounded(cast(cstring)&kinfo.path[0], len(kinfo.path)) return path, nil } -absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { +absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { rel = "." @@ -737,7 +738,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } defer _unix_free(path_ptr) @@ -747,13 +748,13 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { return path, nil } -access :: proc(path: string, mask: int) -> (bool, Errno) { +access :: proc(path: string, mask: int) -> (bool, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) result := _unix_access(cstr, c.int(mask)) if result == -1 { - return false, Errno(get_last_error()) + return false, Error(get_last_error()) } return true, nil } @@ -785,7 +786,7 @@ get_current_directory :: proc() -> string { if cwd != nil { return string(cwd) } - if Errno(get_last_error()) != ERANGE { + if Error(get_last_error()) != ERANGE { delete(buf) return "" } @@ -794,12 +795,12 @@ get_current_directory :: proc() -> string { unreachable() } -set_current_directory :: proc(path: string) -> (err: Errno) { +set_current_directory :: proc(path: string) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index cc748b82b..d7a5c5db8 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -119,7 +119,7 @@ S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK foreign libc { - @(link_name="_errnop") __error :: proc() -> ^c.int --- + @(link_name="_Errorp") __error :: proc() -> ^c.int --- @(link_name="fork") _unix_fork :: proc() -> pid_t --- @(link_name="getthrid") _unix_getthrid :: proc() -> int --- @@ -181,32 +181,33 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } +@(require_results, no_instrumentation) get_last_error :: proc "contextless" () -> Error { return Platform_Error(__error()^) } -fork :: proc() -> (Pid, Errno) { +fork :: proc() -> (Pid, Error) { pid := _unix_fork() if pid == -1 { - return Pid(-1), Errno(get_last_error()) + return Pid(-1), Error(get_last_error()) } return Pid(pid), nil } -open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { - return INVALID_HANDLE, Errno(get_last_error()) + return INVALID_HANDLE, Error(get_last_error()) } return handle, nil } -close :: proc(fd: Handle) -> Errno { +close :: proc(fd: Handle) -> Error { result := _unix_close(fd) if result == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -218,16 +219,16 @@ close :: proc(fd: Handle) -> Errno { @(private) MAX_RW :: 1 << 30 -read :: proc(fd: Handle, data: []byte) -> (int, Errno) { +read :: proc(fd: Handle, data: []byte) -> (int, Error) { to_read := min(c.size_t(len(data)), MAX_RW) bytes_read := _unix_read(fd, &data[0], to_read) if bytes_read == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return int(bytes_read), nil } -write :: proc(fd: Handle, data: []byte) -> (int, Errno) { +write :: proc(fd: Handle, data: []byte) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -235,20 +236,20 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { to_write := min(c.size_t(len(data)), MAX_RW) bytes_written := _unix_write(fd, &data[0], to_write) if bytes_written == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return int(bytes_written), nil } -seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return res, nil } -file_size :: proc(fd: Handle) -> (i64, Errno) { +file_size :: proc(fd: Handle) -> (i64, Error) { s, err := _fstat(fd) if err != nil { return -1, err @@ -268,7 +269,7 @@ _alloc_command_line_arguments :: proc() -> []string { } @private -_stat :: proc(path: string) -> (OS_Stat, Errno) { +_stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -276,13 +277,13 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { s: OS_Stat = --- res := _unix_stat(cstr, &s) if res == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_lstat :: proc(path: string) -> (OS_Stat, Errno) { +_lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -290,36 +291,36 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { s: OS_Stat = --- res := _unix_lstat(cstr, &s) if res == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { +_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { // deliberately uninitialized s: OS_Stat = --- res := _unix_fstat(fd, &s) if res == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_fdopendir :: proc(fd: Handle) -> (Dir, Errno) { +_fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Errno(get_last_error()) + return nil, Error(get_last_error()) } return dirp, nil } @private -_closedir :: proc(dirp: Dir) -> Errno { +_closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -330,12 +331,12 @@ _rewinddir :: proc(dirp: Dir) { } @private -_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) { +_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Errno(get_last_error()) + err = Error(get_last_error()) return } @@ -348,7 +349,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) } @private -_readlink :: proc(path: string) -> (string, Errno) { +_readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -358,7 +359,7 @@ _readlink :: proc(path: string) -> (string, Errno) { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) if rc == -1 { delete(buf) - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } else if rc == int(bufsz) { bufsz += MAX_PATH delete(buf) @@ -369,11 +370,11 @@ _readlink :: proc(path: string) -> (string, Errno) { } } -absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { - return "", Errno(ENOSYS) +absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { + return "", Error(ENOSYS) } -absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { +absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { rel = "." @@ -384,7 +385,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } defer _unix_free(path_ptr) @@ -394,12 +395,12 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { return path, nil } -access :: proc(path: string, mask: int) -> (bool, Errno) { +access :: proc(path: string, mask: int) -> (bool, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_access(cstr, c.int(mask)) if res == -1 { - return false, Errno(get_last_error()) + return false, Error(get_last_error()) } return true, nil } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 985070eb2..42a10a874 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -520,6 +520,7 @@ _get_errno :: proc(res: int) -> Error { } // get errno from libc +@(require_results, no_instrumentation) get_last_error :: proc "contextless" () -> Error { err := Platform_Error(__errno_location()^) #partial switch err { diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index ed9d81dfe..d99a31f0a 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -150,7 +150,7 @@ _Platform_Error :: enum i32 { EOWNERDEAD = 97, /* Previous owner died */ ENOTRECOVERABLE = 98, /* State not recoverable */ - ELAST = 98, /* Must equal largest errno */ + ELAST = 98, /* Must equal largest Error */ } EPERM :: Platform_Error.EPERM /* Operation not permitted */ @@ -289,9 +289,9 @@ EPROTO :: Platform_Error.EPROTO /* Protocol error */ EOWNERDEAD :: Platform_Error.EOWNERDEAD /* Previous owner died */ ENOTRECOVERABLE :: Platform_Error.ENOTRECOVERABLE /* State not recoverable */ -ELAST :: Platform_Error.ELAST /* Must equal largest errno */ +ELAST :: Platform_Error.ELAST /* Must equal largest Error */ -/* end of errno */ +/* end of Error */ O_RDONLY :: 0x000000000 O_WRONLY :: 0x000000001 @@ -421,7 +421,7 @@ W_OK :: 2 // Test for write permission R_OK :: 4 // Test for read permission foreign libc { - @(link_name="__errno") __errno_location :: proc() -> ^c.int --- + @(link_name="__Error") __Error_location :: proc() -> ^c.int --- @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- @@ -473,28 +473,31 @@ foreign libc { // NOTE(phix): Perhaps share the following functions with FreeBSD if they turn out to be the same in the end. +@(require_results) is_path_separator :: proc(r: rune) -> bool { return r == '/' } +@(require_results, no_instrumentation) get_last_error :: proc "contextless" () -> Error { - return Platform_Error(__errno_location()^) + return Platform_Error(__Error_location()^) } -open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { +@(require_results) +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { - return INVALID_HANDLE, Errno(get_last_error()) + return INVALID_HANDLE, Error(get_last_error()) } return handle, nil } -close :: proc(fd: Handle) -> Errno { +close :: proc(fd: Handle) -> Error { result := _unix_close(fd) if result == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -503,16 +506,16 @@ close :: proc(fd: Handle) -> Errno { @(private) MAX_RW :: 1 << 30 -read :: proc(fd: Handle, data: []byte) -> (int, Errno) { +read :: proc(fd: Handle, data: []byte) -> (int, Error) { to_read := min(c.size_t(len(data)), MAX_RW) bytes_read := _unix_read(fd, &data[0], to_read) if bytes_read == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return int(bytes_read), nil } -write :: proc(fd: Handle, data: []byte) -> (int, Errno) { +write :: proc(fd: Handle, data: []byte) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -520,63 +523,63 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { to_write := min(c.size_t(len(data)), MAX_RW) bytes_written := _unix_write(fd, &data[0], to_write) if bytes_written == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return int(bytes_written), nil } -seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return res, nil } -file_size :: proc(fd: Handle) -> (size: i64, err: Errno) { +file_size :: proc(fd: Handle) -> (size: i64, err: Error) { size = -1 s := _fstat(fd) or_return size = s.size return } -rename :: proc(old_path, new_path: string) -> Errno { +rename :: proc(old_path, new_path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) res := _unix_rename(old_path_cstr, new_path_cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -remove :: proc(path: string) -> Errno { +remove :: proc(path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_unlink(path_cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { +make_directory :: proc(path: string, mode: mode_t = 0o775) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -remove_directory :: proc(path: string) -> Errno { +remove_directory :: proc(path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_rmdir(path_cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -591,7 +594,7 @@ is_file_handle :: proc(fd: Handle) -> bool { is_file_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat - err: Errno + err: Error if follow_links { s, err = _stat(path) } else { @@ -613,7 +616,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat - err: Errno + err: Error if follow_links { s, err = _stat(path) } else { @@ -635,10 +638,10 @@ exists :: proc(path: string) -> bool { return res == 0 } -fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { +fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Error) { result := _unix_fcntl(Handle(fd), c.int(cmd), uintptr(arg)) if result < 0 { - return 0, Errno(get_last_error()) + return 0, Error(get_last_error()) } return int(result), nil } @@ -649,32 +652,32 @@ stdin: Handle = 0 stdout: Handle = 1 stderr: Handle = 2 -last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Errno) { +last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Error) { s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } -last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Errno) { +last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } @private -_stat :: proc(path: string) -> (OS_Stat, Errno) { +_stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) s: OS_Stat = --- result := _unix_lstat(cstr, &s) if result == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_lstat :: proc(path: string) -> (OS_Stat, Errno) { +_lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -682,35 +685,35 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { s: OS_Stat = --- res := _unix_lstat(cstr, &s) if res == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { +_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat = --- result := _unix_fstat(fd, &s) if result == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_fdopendir :: proc(fd: Handle) -> (Dir, Errno) { +_fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Errno(get_last_error()) + return nil, Error(get_last_error()) } return dirp, nil } @private -_closedir :: proc(dirp: Dir) -> Errno { +_closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -721,12 +724,12 @@ _rewinddir :: proc(dirp: Dir) { } @private -_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) { +_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Errno(get_last_error()) + err = Error(get_last_error()) return } err = nil @@ -740,7 +743,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) } @private -_readlink :: proc(path: string) -> (string, Errno) { +_readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -751,7 +754,7 @@ _readlink :: proc(path: string) -> (string, Errno) { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) if rc == -1 { delete(buf) - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } else if rc == int(bufsz) { bufsz += MAX_PATH delete(buf) @@ -761,16 +764,16 @@ _readlink :: proc(path: string) -> (string, Errno) { } } - return "", Errno{} + return "", Error{} } -absolute_path_from_handle :: proc(fd: Handle) -> (path: string, err: Errno) { +absolute_path_from_handle :: proc(fd: Handle) -> (path: string, err: Error) { buf: [MAX_PATH]byte _ = fcntl(int(fd), F_GETPATH, int(uintptr(&buf[0]))) or_return return strings.clone_from_cstring(cstring(&buf[0])) } -absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { +absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { rel = "." @@ -781,7 +784,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } defer _unix_free(path_ptr) @@ -790,13 +793,13 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { return path, nil } -access :: proc(path: string, mask: int) -> (bool, Errno) { +access :: proc(path: string, mask: int) -> (bool, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) result := _unix_access(cstr, c.int(mask)) if result == -1 { - return false, Errno(get_last_error()) + return false, Error(get_last_error()) } return true, nil } @@ -828,7 +831,7 @@ get_current_directory :: proc() -> string { if cwd != nil { return string(cwd) } - if Errno(get_last_error()) != ERANGE { + if Error(get_last_error()) != ERANGE { delete(buf) return "" } @@ -837,12 +840,12 @@ get_current_directory :: proc() -> string { unreachable() } -set_current_directory :: proc(path: string) -> (err: Errno) { +set_current_directory :: proc(path: string) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 9ecdbbc98..1309d0c0d 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -388,36 +388,40 @@ foreign libc { @(link_name="dlerror") _unix_dlerror :: proc() -> cstring --- } +@(require_results) is_path_separator :: proc(r: rune) -> bool { return r == '/' } +@(require_results, no_instrumentation) get_last_error :: proc "contextless" () -> Error { return Platform_Error(__error()^) } -fork :: proc() -> (Pid, Errno) { +@(require_results) +fork :: proc() -> (Pid, Error) { pid := _unix_fork() if pid == -1 { - return Pid(-1), Errno(get_last_error()) + return Pid(-1), Error(get_last_error()) } return Pid(pid), nil } -open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { +@(require_results) +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { - return INVALID_HANDLE, Errno(get_last_error()) + return INVALID_HANDLE, Error(get_last_error()) } return handle, nil } -close :: proc(fd: Handle) -> Errno { +close :: proc(fd: Handle) -> Error { result := _unix_close(fd) if result == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -430,16 +434,16 @@ close :: proc(fd: Handle) -> Errno { @(private) MAX_RW :: 1 << 30 -read :: proc(fd: Handle, data: []byte) -> (int, Errno) { +read :: proc(fd: Handle, data: []byte) -> (int, Error) { to_read := min(c.size_t(len(data)), MAX_RW) bytes_read := _unix_read(fd, &data[0], to_read) if bytes_read == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return int(bytes_read), nil } -write :: proc(fd: Handle, data: []byte) -> (int, Errno) { +write :: proc(fd: Handle, data: []byte) -> (int, Error) { if len(data) == 0 { return 0, nil } @@ -447,63 +451,63 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { to_write := min(c.size_t(len(data)), MAX_RW) bytes_written := _unix_write(fd, &data[0], to_write) if bytes_written == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return int(bytes_written), nil } -seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { - return -1, Errno(get_last_error()) + return -1, Error(get_last_error()) } return res, nil } -file_size :: proc(fd: Handle) -> (size: i64, err: Errno) { +file_size :: proc(fd: Handle) -> (size: i64, err: Error) { size = -1 s := _fstat(fd) or_return size = s.size return } -rename :: proc(old_path, new_path: string) -> Errno { +rename :: proc(old_path, new_path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) res := _unix_rename(old_path_cstr, new_path_cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -remove :: proc(path: string) -> Errno { +remove :: proc(path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_unlink(path_cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { +make_directory :: proc(path: string, mode: mode_t = 0o775) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } -remove_directory :: proc(path: string) -> Errno { +remove_directory :: proc(path: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_rmdir(path_cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -518,7 +522,7 @@ is_file_handle :: proc(fd: Handle) -> bool { is_file_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat - err: Errno + err: Error if follow_links { s, err = _stat(path) } else { @@ -540,7 +544,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat - err: Errno + err: Error if follow_links { s, err = _stat(path) } else { @@ -565,20 +569,20 @@ stderr: Handle = 2 last_write_time :: proc(fd: Handle) -> File_Time {} last_write_time_by_name :: proc(name: string) -> File_Time {} */ -last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Errno) { +last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Error) { s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } -last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Errno) { +last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } @private -_stat :: proc(path: string) -> (OS_Stat, Errno) { +_stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -586,13 +590,13 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { s: OS_Stat = --- res := _unix_stat(cstr, &s) if res == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_lstat :: proc(path: string) -> (OS_Stat, Errno) { +_lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -600,36 +604,36 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { s: OS_Stat = --- res := _unix_lstat(cstr, &s) if res == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { +_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { // deliberately uninitialized s: OS_Stat = --- res := _unix_fstat(fd, &s) if res == -1 { - return s, Errno(get_last_error()) + return s, Error(get_last_error()) } return s, nil } @private -_fdopendir :: proc(fd: Handle) -> (Dir, Errno) { +_fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Errno(get_last_error()) + return nil, Error(get_last_error()) } return dirp, nil } @private -_closedir :: proc(dirp: Dir) -> Errno { +_closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } @@ -640,12 +644,12 @@ _rewinddir :: proc(dirp: Dir) { } @private -_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) { +_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Errno(get_last_error()) + err = Error(get_last_error()) return } err = nil @@ -659,7 +663,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) } @private -_readlink :: proc(path: string) -> (string, Errno) { +_readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -669,7 +673,7 @@ _readlink :: proc(path: string) -> (string, Errno) { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) if rc == -1 { delete(buf) - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } else if rc == int(bufsz) { bufsz += MAX_PATH delete(buf) @@ -681,11 +685,11 @@ _readlink :: proc(path: string) -> (string, Errno) { } // XXX OpenBSD -absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { - return "", Errno(ENOSYS) +absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { + return "", Error(ENOSYS) } -absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { +absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { rel = "." @@ -696,7 +700,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Errno(get_last_error()) + return "", Error(get_last_error()) } defer _unix_free(path_ptr) @@ -705,12 +709,12 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { return path, nil } -access :: proc(path: string, mask: int) -> (bool, Errno) { +access :: proc(path: string, mask: int) -> (bool, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_access(cstr, c.int(mask)) if res == -1 { - return false, Errno(get_last_error()) + return false, Error(get_last_error()) } return true, nil } @@ -737,7 +741,7 @@ get_current_directory :: proc() -> string { if cwd != nil { return string(cwd) } - if Errno(get_last_error()) != ERANGE { + if Error(get_last_error()) != ERANGE { delete(buf) return "" } @@ -746,12 +750,12 @@ get_current_directory :: proc() -> string { unreachable() } -set_current_directory :: proc(path: string) -> (err: Errno) { +set_current_directory :: proc(path: string) -> (err: Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 { - return Errno(get_last_error()) + return Error(get_last_error()) } return nil } diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 574431c4c..58f03f279 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -63,6 +63,7 @@ ERROR_NEGATIVE_OFFSET :: _Platform_Error(1<<29 + 2) // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() +@(require_results, no_instrumentation) get_last_error :: proc "contextless" () -> Error { err := win32.GetLastError() if err == 0 { @@ -114,6 +115,7 @@ get_last_error :: proc "contextless" () -> Error { } +@(require_results) last_write_time :: proc(fd: Handle) -> (File_Time, Error) { file_info: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(win32.HANDLE(fd), &file_info) { @@ -124,6 +126,7 @@ last_write_time :: proc(fd: Handle) -> (File_Time, Error) { return lo | hi << 32, nil } +@(require_results) last_write_time_by_name :: proc(name: string) -> (File_Time, Error) { data: win32.WIN32_FILE_ATTRIBUTE_DATA @@ -138,6 +141,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Error) { } +@(require_results) get_page_size :: proc() -> int { // NOTE(tetra): The page size never changes, so why do anything complicated // if we don't have to. diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin index 6a9ac9dee..d886d71da 100644 --- a/core/path/filepath/path_windows.odin +++ b/core/path/filepath/path_windows.odin @@ -63,17 +63,17 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Error) { p := win32.utf8_to_utf16(name, ta) n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil) if n == 0 { - return "", os.Platform_Error(win32.GetLastError()) + return "", os.get_last_error() } buf := make([]u16, n, ta) n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) if n == 0 { delete(buf) - return "", os.Platform_Error(win32.GetLastError()) + return "", os.get_last_error() } - return win32.utf16_to_utf8(buf[:n], ta) or_else "", os.ERROR_NONE + return win32.utf16_to_utf8(buf[:n], ta) } diff --git a/core/prof/spall/spall.odin b/core/prof/spall/spall.odin index 38c563248..12f082b2c 100644 --- a/core/prof/spall/spall.odin +++ b/core/prof/spall/spall.odin @@ -68,7 +68,7 @@ BUFFER_DEFAULT_SIZE :: 0x10_0000 context_create_with_scale :: proc(filename: string, precise_time: bool, timestamp_scale: f64) -> (ctx: Context, ok: bool) #optional_ok { fd, err := os.open(filename, os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, 0o600) - if err != os.ERROR_NONE { + if err != nil { return } diff --git a/core/prof/spall/spall_linux.odin b/core/prof/spall/spall_linux.odin index deee15aa1..89a4225d3 100644 --- a/core/prof/spall/spall_linux.odin +++ b/core/prof/spall/spall_linux.odin @@ -12,19 +12,19 @@ MAX_RW :: 0x7fffffff @(no_instrumentation) _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { if len(data) == 0 { - return 0, os.ERROR_NONE + return 0, nil } for n < len(data) { chunk := data[:min(len(data), MAX_RW)] written, errno := linux.write(linux.Fd(fd), chunk) - if errno != .NONE { - return n, os.Error(errno) + if errno != nil { + return n, os.Platform_Error(errno) } n += written } - return n, os.ERROR_NONE + return n, nil } CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP. diff --git a/core/prof/spall/spall_unix.odin b/core/prof/spall/spall_unix.odin index 6da57ee95..174b3a11b 100644 --- a/core/prof/spall/spall_unix.odin +++ b/core/prof/spall/spall_unix.odin @@ -22,29 +22,24 @@ foreign libc { @(link_name="clock_gettime") _unix_clock_gettime :: proc(clock_id: u64, timespec: ^timespec) -> i32 --- } -@(no_instrumentation) -get_last_error :: proc "contextless" () -> os.Platform_Error { - return os.Platform_Error(__error()^) -} - MAX_RW :: 0x7fffffff @(no_instrumentation) _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { if len(data) == 0 { - return 0, os.ERROR_NONE + return 0, nil } for n < len(data) { chunk := data[:min(len(data), MAX_RW)] written := _unix_write(fd, raw_data(chunk), len(chunk)) if written < 0 { - return n, os.Error(get_last_error()) + return n, os.get_last_error() } n += written } - return n, os.ERROR_NONE + return n, nil } CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP. diff --git a/core/prof/spall/spall_windows.odin b/core/prof/spall/spall_windows.odin index 105a61891..c8b044963 100644 --- a/core/prof/spall/spall_windows.odin +++ b/core/prof/spall/spall_windows.odin @@ -12,7 +12,7 @@ MAX_RW :: 1<<30 @(no_instrumentation) _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (int, os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { if len(data) == 0 { - return 0, os.ERROR_NONE + return 0, nil } single_write_length: win32.DWORD @@ -25,12 +25,11 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (int, os.Error) #n e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil) if single_write_length <= 0 || !e { - err := os.Platform_Error(win32.GetLastError()) - return int(total_write), err + return int(total_write), os.get_last_error() } total_write += i64(single_write_length) } - return int(total_write), os.ERROR_NONE + return int(total_write), nil } @(no_instrumentation) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index da0328f91..16967e3c7 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -868,8 +868,8 @@ To partly mitigate this, redirect STDERR to a file or use the -define:ODIN_TEST_ when ODIN_OS != .Windows { mode = os.S_IRUSR|os.S_IWUSR|os.S_IRGRP|os.S_IROTH } - json_fd, errno := os.open(JSON_REPORT, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) - fmt.assertf(errno == os.ERROR_NONE, "unable to open file %q for writing of JSON report, error: %v", JSON_REPORT, errno) + json_fd, err := os.open(JSON_REPORT, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) + fmt.assertf(err == nil, "unable to open file %q for writing of JSON report, error: %v", JSON_REPORT, err) defer os.close(json_fd) for test, i in report.all_tests { diff --git a/tests/core/flags/test_core_flags.odin b/tests/core/flags/test_core_flags.odin index e32c6832c..f8305f2ea 100644 --- a/tests/core/flags/test_core_flags.odin +++ b/tests/core/flags/test_core_flags.odin @@ -1117,7 +1117,7 @@ test_os_handle :: proc(t: ^testing.T) { // Delete the file now that we're done. // // This is not done all the time, just in case the file is useful to debugging. - testing.expect_value(t, os.remove(TEMPORARY_FILENAME), os.ERROR_NONE) + testing.expect_value(t, os.remove(TEMPORARY_FILENAME), nil) } TEMPORARY_FILENAME :: "test_core_flags_write_test_output_data" diff --git a/tests/core/os/os.odin b/tests/core/os/os.odin index fd4fd28a8..97ceaeb1e 100644 --- a/tests/core/os/os.odin +++ b/tests/core/os/os.odin @@ -7,12 +7,12 @@ import "core:testing" @(test) read_dir :: proc(t: ^testing.T) { - fd, errno := os.open(#directory + "/dir") - testing.expect_value(t, errno, os.ERROR_NONE) + fd, err := os.open(#directory + "/dir") + testing.expect_value(t, err, nil) defer os.close(fd) - dir, errno2 := os.read_dir(fd, -1) - testing.expect_value(t, errno2, os.ERROR_NONE) + dir, err2 := os.read_dir(fd, -1) + testing.expect_value(t, err2, nil) defer os.file_info_slice_delete(dir) slice.sort_by_key(dir, proc(fi: os.File_Info) -> string { return fi.name }) diff --git a/tests/documentation/documentation_tester.odin b/tests/documentation/documentation_tester.odin index 8a798d6c5..ce1849e1c 100644 --- a/tests/documentation/documentation_tester.odin +++ b/tests/documentation/documentation_tester.odin @@ -439,7 +439,7 @@ main :: proc() { } save_path := fmt.tprintf("verify/test_%v_%v.odin", test.package_name, code_test_name) - test_file_handle, err := os.open(save_path, os.O_WRONLY | os.O_CREATE); if err != 0 { + test_file_handle, err := os.open(save_path, os.O_WRONLY | os.O_CREATE); if err != nil { fmt.eprintf("We could not open the file to the path %q for writing\n", save_path) g_bad_doc = true continue From 5187bb68bb46a508c90c83861973c57b8e89d005 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 12:08:52 +0100 Subject: [PATCH 067/122] Hack: Convert `0` to `nil` --- src/check_expr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9efd16af4..06784a7f3 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4470,7 +4470,10 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar if (is_exact_value_zero(operand->value) && (operand->value.kind == ExactValue_Integer || operand->value.kind == ExactValue_Float)) { - update_untyped_expr_value(c, operand->expr, empty_exact_value); + operand->mode = Addressing_Value; + target_type = t_untyped_nil; + operand->value = empty_exact_value; + update_untyped_expr_value(c, operand->expr, operand->value); break; } } From 66b86bc7e02d7b43f869f5ce1c3451515b291cdd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 12:23:18 +0100 Subject: [PATCH 068/122] Correct os errors for darwin --- core/net/socket_darwin.odin | 46 ++-- core/os/os_darwin.odin | 459 +++++++++++++++++++----------------- 2 files changed, 266 insertions(+), 239 deletions(-) diff --git a/core/net/socket_darwin.odin b/core/net/socket_darwin.odin index 1cee33d1d..10069963a 100644 --- a/core/net/socket_darwin.odin +++ b/core/net/socket_darwin.odin @@ -85,7 +85,7 @@ _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_optio sockaddr := _endpoint_to_sockaddr(endpoint) res := os.connect(os.Socket(skt), (^os.SOCKADDR)(&sockaddr), i32(sockaddr.len)) if res != nil { - err = Dial_Error(res) + err = Dial_Error(os.is_platform_error(res) or_else -1) return } @@ -104,7 +104,7 @@ _bind :: proc(skt: Any_Socket, ep: Endpoint) -> (err: Network_Error) { if res == os.EACCES && ep.port <= MAX_PRIVILEGED_PORT { err = .Privileged_Port_Without_Root } else { - err = Bind_Error(res) + err = Bind_Error(os.is_platform_error(res) or_else -1) } } return @@ -129,7 +129,7 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (skt: TCP_ res := os.listen(os.Socket(skt), backlog) if res != nil { - err = Listen_Error(res) + err = Listen_Error(os.is_platform_error(res) or_else -1) return } @@ -162,9 +162,9 @@ _recv_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_read: int, err: Networ if len(buf) <= 0 { return } - res, ok := os.recv(os.Socket(skt), buf, 0) - if ok != os.ERROR_NONE { - err = TCP_Recv_Error(ok) + res, res_err := os.recv(os.Socket(skt), buf, 0) + if res_err != nil { + err = TCP_Recv_Error(os.is_platform_error(res_err) or_else -1) return } return int(res), nil @@ -178,9 +178,9 @@ _recv_udp :: proc(skt: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endp from: os.SOCKADDR_STORAGE_LH fromsize := c.int(size_of(from)) - res, ok := os.recvfrom(os.Socket(skt), buf, 0, cast(^os.SOCKADDR) &from, &fromsize) - if ok != os.ERROR_NONE { - err = UDP_Recv_Error(ok) + res, res_err := os.recvfrom(os.Socket(skt), buf, 0, cast(^os.SOCKADDR) &from, &fromsize) + if res_err != nil { + err = UDP_Recv_Error(os.is_platform_error(res_err) or_else -1) return } @@ -194,9 +194,9 @@ _send_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Net for bytes_written < len(buf) { limit := min(int(max(i32)), len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] - res, ok := os.send(os.Socket(skt), remaining, 0) - if ok != os.ERROR_NONE { - err = TCP_Send_Error(ok) + res, res_err := os.send(os.Socket(skt), remaining, 0) + if res_err != nil { + err = TCP_Send_Error(os.is_platform_error(res_err) or_else -1) return } bytes_written += int(res) @@ -210,9 +210,9 @@ _send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: for bytes_written < len(buf) { limit := min(1<<31, len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] - res, ok := os.sendto(os.Socket(skt), remaining, 0, cast(^os.SOCKADDR)&toaddr, i32(toaddr.len)) - if ok != os.ERROR_NONE { - err = UDP_Send_Error(ok) + res, res_err := os.sendto(os.Socket(skt), remaining, 0, cast(^os.SOCKADDR)&toaddr, i32(toaddr.len)) + if res_err != nil { + err = UDP_Send_Error(os.is_platform_error(res_err) or_else -1) return } bytes_written += int(res) @@ -224,8 +224,8 @@ _send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: _shutdown :: proc(skt: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { s := any_socket_to_socket(skt) res := os.shutdown(os.Socket(s), int(manner)) - if res != os.ERROR_NONE { - return Shutdown_Error(res) + if res != nil { + return Shutdown_Error(os.is_platform_error(res) or_else -1) } return } @@ -302,8 +302,8 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca skt := any_socket_to_socket(s) res := os.setsockopt(os.Socket(skt), int(level), int(option), ptr, len) - if res != os.ERROR_NONE { - return Socket_Option_Error(res) + if res != nil { + return Socket_Option_Error(os.is_platform_error(res) or_else -1) } return nil @@ -314,8 +314,8 @@ _set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_E socket := any_socket_to_socket(socket) flags, getfl_err := os.fcntl(int(socket), os.F_GETFL, 0) - if getfl_err != os.ERROR_NONE { - return Set_Blocking_Error(getfl_err) + if getfl_err != nil { + return Set_Blocking_Error(os.is_platform_error(getfl_err) or_else -1) } if should_block { @@ -325,8 +325,8 @@ _set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_E } _, setfl_err := os.fcntl(int(socket), os.F_SETFL, flags) - if setfl_err != os.ERROR_NONE { - return Set_Blocking_Error(setfl_err) + if setfl_err != nil { + return Set_Blocking_Error(os.is_platform_error(setfl_err) or_else -1) } return nil diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index d40044f7e..420b8678d 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -15,252 +15,279 @@ INVALID_HANDLE :: ~Handle(0) _Platform_Error :: enum i32 { NONE = 0, - EPERM = 1, /* Operation not permitted */ - ENOENT = 2, /* No such file or directory */ - ESRCH = 3, /* No such process */ - EINTR = 4, /* Interrupted system call */ - EIO = 5, /* Input/output error */ - ENXIO = 6, /* Device not configured */ - E2BIG = 7, /* Argument list too long */ - ENOEXEC = 8, /* Exec format error */ - EBADF = 9, /* Bad file descriptor */ - ECHILD = 10, /* No child processes */ - EDEADLK = 11, /* Resource deadlock avoided */ - ENOMEM = 12, /* Cannot allocate memory */ - EACCES = 13, /* Permission denied */ - EFAULT = 14, /* Bad address */ - ENOTBLK = 15, /* Block device required */ - EBUSY = 16, /* Device / Resource busy */ - EEXIST = 17, /* File exists */ - EXDEV = 18, /* Cross-device link */ - ENODEV = 19, /* Operation not supported by device */ - ENOTDIR = 20, /* Not a directory */ - EISDIR = 21, /* Is a directory */ - EINVAL = 22, /* Invalid argument */ - ENFILE = 23, /* Too many open files in system */ - EMFILE = 24, /* Too many open files */ - ENOTTY = 25, /* Inappropriate ioctl for device */ - ETXTBSY = 26, /* Text file busy */ - EFBIG = 27, /* File too large */ - ENOSPC = 28, /* No space left on device */ - ESPIPE = 29, /* Illegal seek */ - EROFS = 30, /* Read-only file system */ - EMLINK = 31, /* Too many links */ - EPIPE = 32, /* Broken pipe */ + EPERM = 1, /* Operation not permitted */ + ENOENT = 2, /* No such file or directory */ + ESRCH = 3, /* No such process */ + EINTR = 4, /* Interrupted system call */ + EIO = 5, /* Input/output error */ + ENXIO = 6, /* Device not configured */ + E2BIG = 7, /* Argument list too long */ + ENOEXEC = 8, /* Exec format error */ + EBADF = 9, /* Bad file descriptor */ + ECHILD = 10, /* No child processes */ + EDEADLK = 11, /* Resource deadlock avoided */ + ENOMEM = 12, /* Cannot allocate memory */ + EACCES = 13, /* Permission denied */ + EFAULT = 14, /* Bad address */ + ENOTBLK = 15, /* Block device required */ + EBUSY = 16, /* Device / Resource busy */ + EEXIST = 17, /* File exists */ + EXDEV = 18, /* Cross-device link */ + ENODEV = 19, /* Operation not supported by device */ + ENOTDIR = 20, /* Not a directory */ + EISDIR = 21, /* Is a directory */ + EINVAL = 22, /* Invalid argument */ + ENFILE = 23, /* Too many open files in system */ + EMFILE = 24, /* Too many open files */ + ENOTTY = 25, /* Inappropriate ioctl for device */ + ETXTBSY = 26, /* Text file busy */ + EFBIG = 27, /* File too large */ + ENOSPC = 28, /* No space left on device */ + ESPIPE = 29, /* Illegal seek */ + EROFS = 30, /* Read-only file system */ + EMLINK = 31, /* Too many links */ + EPIPE = 32, /* Broken pipe */ /* math software */ - EDOM = 33, /* Numerical argument out of domain */ - ERANGE = 34, /* Result too large */ + EDOM = 33, /* Numerical argument out of domain */ + ERANGE = 34, /* Result too large */ /* non-blocking and interrupt i/o */ - EAGAIN = 35, /* Resource temporarily unavailable */ - EWOULDBLOCK = EAGAIN, /* Operation would block */ - EINPROGRESS = 36, /* Operation now in progress */ - EALREADY = 37, /* Operation already in progress */ + EAGAIN = 35, /* Resource temporarily unavailable */ + EWOULDBLOCK = EAGAIN, /* Operation would block */ + EINPROGRESS = 36, /* Operation now in progress */ + EALREADY = 37, /* Operation already in progress */ /* ipc/network software -- argument errors */ - ENOTSOCK = 38, /* Socket operation on non-socket */ - EDESTADDRREQ = 39, /* Destination address required */ - EMSGSIZE = 40, /* Message too long */ - EPROTOTYPE = 41, /* Protocol wrong type for socket */ - ENOPROTOOPT = 42, /* Protocol not available */ - EPROTONOSUPPOR = 43, /* Protocol not supported */ - ESOCKTNOSUPPOR = 44, /* Socket type not supported */ - ENOTSUP = 45, /* Operation not supported */ - EOPNOTSUPP = ENOTSUP, - EPFNOSUPPORT = 46, /* Protocol family not supported */ - EAFNOSUPPORT = 47, /* Address family not supported by protocol family */ - EADDRINUSE = 48, /* Address already in use */ - EADDRNOTAVAIL = 49, /* Can't assign requested address */ + ENOTSOCK = 38, /* Socket operation on non-socket */ + EDESTADDRREQ = 39, /* Destination address required */ + EMSGSIZE = 40, /* Message too long */ + EPROTOTYPE = 41, /* Protocol wrong type for socket */ + ENOPROTOOPT = 42, /* Protocol not available */ + EPROTONOSUPPORT = 43, /* Protocol not supported */ + ESOCKTNOSUPPORT = 44, /* Socket type not supported */ + ENOTSUP = 45, /* Operation not supported */ + EOPNOTSUPP = ENOTSUP, + EPFNOSUPPORT = 46, /* Protocol family not supported */ + EAFNOSUPPORT = 47, /* Address family not supported by protocol family */ + EADDRINUSE = 48, /* Address already in use */ + EADDRNOTAVAIL = 49, /* Can't assign requested address */ /* ipc/network software -- operational errors */ - ENETDOWN = 50, /* Network is down */ - ENETUNREAC = 51, /* Network is unreachable */ - ENETRESET = 52, /* Network dropped connection on reset */ - ECONNABORTE = 53, /* Software caused connection abort */ - ECONNRESET = 54, /* Connection reset by peer */ - ENOBUFS = 55, /* No buffer space available */ - EISCONN = 56, /* Socket is already connected */ - ENOTCONN = 57, /* Socket is not connected */ - ESHUTDOWN = 58, /* Can't send after socket shutdown */ - ETOOMANYREF = 59, /* Too many references: can't splice */ - ETIMEDOUT = 60, /* Operation timed out */ - ECONNREFUSE = 61, /* Connection refused */ + ENETDOWN = 50, /* Network is down */ + ENETUNREACH = 51, /* Network is unreachable */ + ENETRESET = 52, /* Network dropped connection on reset */ + ECONNABORTED = 53, /* Software caused connection abort */ + ECONNRESET = 54, /* Connection reset by peer */ + ENOBUFS = 55, /* No buffer space available */ + EISCONN = 56, /* Socket is already connected */ + ENOTCONN = 57, /* Socket is not connected */ + ESHUTDOWN = 58, /* Can't send after socket shutdown */ + ETOOMANYREFS = 59, /* Too many references: can't splice */ + ETIMEDOUT = 60, /* Operation timed out */ + ECONNREFUSED = 61, /* Connection refused */ - ELOOP = 62, /* Too many levels of symbolic links */ - ENAMETOOLON = 63, /* File name too long */ + ELOOP = 62, /* Too many levels of symbolic links */ + ENAMETOOLONG = 63, /* File name too long */ /* should be rearranged */ - EHOSTDOWN = 64, /* Host is down */ - EHOSTUNREAC = 65, /* No route to host */ - ENOTEMPTY = 66, /* Directory not empty */ + EHOSTDOWN = 64, /* Host is down */ + EHOSTUNREACH = 65, /* No route to host */ + ENOTEMPTY = 66, /* Directory not empty */ /* quotas & mush */ - EPROCLIM = 67, /* Too many processes */ - EUSERS = 68, /* Too many users */ - EDQUOT = 69, /* Disc quota exceeded */ + EPROCLIM = 67, /* Too many processes */ + EUSERS = 68, /* Too many users */ + EDQUOT = 69, /* Disc quota exceeded */ /* Network File System */ - ESTALE = 70, /* Stale NFS file handle */ - EREMOTE = 71, /* Too many levels of remote in path */ - EBADRPC = 72, /* RPC struct is bad */ - ERPCMISMATC = 73, /* RPC version wrong */ - EPROGUNAVAI = 74, /* RPC prog. not avail */ - EPROGMISMATC = 75, /* Program version wrong */ - EPROCUNAVAI = 76, /* Bad procedure for program */ + ESTALE = 70, /* Stale NFS file handle */ + EREMOTE = 71, /* Too many levels of remote in path */ + EBADRPC = 72, /* RPC struct is bad */ + ERPCMISMATCH = 73, /* RPC version wrong */ + EPROGUNAVAIL = 74, /* RPC prog. not avail */ + EPROGMISMATCH = 75, /* Program version wrong */ + EPROCUNAVAIL = 76, /* Bad procedure for program */ - ENOLC = 77, /* No locks available */ - ENOSY = 78, /* Function not implemented */ + ENOLCK = 77, /* No locks available */ + ENOSYS = 78, /* Function not implemented */ - EFTYP = 79, /* Inappropriate file type or format */ - EAUT = 80, /* Authentication error */ - ENEEDAUT = 81, /* Need authenticator */ + EFTYPE = 79, /* Inappropriate file type or format */ + EAUTH = 80, /* Authentication error */ + ENEEDAUTH = 81, /* Need authenticator */ /* Intelligent device errors */ - EPWROF = 82, /* Device power is off */ - EDEVER = 83, /* Device error, e.g. paper out */ - EOVERFLO = 84, /* Value too large to be stored in data type */ + EPWROFF = 82, /* Device power is off */ + EDEVERR = 83, /* Device error, e.g. paper out */ + EOVERFLOW = 84, /* Value too large to be stored in data type */ /* Program loading errors */ - EBADEXE = 85, /* Bad executable */ - EBADARC = 86, /* Bad CPU type in executable */ - ESHLIBVER = 87, /* Shared library version mismatch */ - EBADMACH = 88, /* Malformed Macho file */ + EBADEXEC = 85, /* Bad executable */ + EBADARCH = 86, /* Bad CPU type in executable */ + ESHLIBVERS = 87, /* Shared library version mismatch */ + EBADMACHO = 88, /* Malformed Macho file */ - ECANCELE = 89, /* Operation canceled */ + ECANCELED = 89, /* Operation canceled */ - EIDRM = 90, /* Identifier removed */ - ENOMSG = 91, /* No message of desired type */ - EILSEQ = 92, /* Illegal byte sequence */ - ENOATT = 93, /* Attribute not found */ + EIDRM = 90, /* Identifier removed */ + ENOMSG = 91, /* No message of desired type */ + EILSEQ = 92, /* Illegal byte sequence */ + ENOATTR = 93, /* Attribute not found */ - EBADMS = 94, /* Bad message */ - EMULTIHO = 95, /* Reserved */ - ENODAT = 96, /* No message available on STREAM */ - ENOLIN = 97, /* Reserved */ - ENOSR = 98, /* No STREAM resources */ - ENOSTR = 99, /* Not a STREAM */ - EPROTO = 100, /* Protocol error */ - ETIME = 101, /* STREAM ioctl timeout */ + EBADMSG = 94, /* Bad message */ + EMULTIHOP = 95, /* Reserved */ + ENODATA = 96, /* No message available on STREAM */ + ENOLINK = 97, /* Reserved */ + ENOSR = 98, /* No STREAM resources */ + ENOSTR = 99, /* Not a STREAM */ + EPROTO = 100, /* Protocol error */ + ETIME = 101, /* STREAM ioctl timeout */ - ENOPOLIC = 103, /* No such policy registered */ + ENOPOLICY = 103, /* No such policy registered */ - ENOTRECOVERABL = 104, /* State not recoverable */ - EOWNERDEAD = 105, /* Previous owner died */ + ENOTRECOVERABLE = 104, /* State not recoverable */ + EOWNERDEAD = 105, /* Previous owner died */ - EQFUL = 106, /* Interface output queue is full */ - ELAS = 106, /* Must be equal largest Error */ + EQFULL = 106, /* Interface output queue is full */ + ELAST = 106, /* Must be equal largest errno */ } +EPERM :: _Platform_Error.EPERM +ENOENT :: _Platform_Error.ENOENT +ESRCH :: _Platform_Error.ESRCH +EINTR :: _Platform_Error.EINTR +EIO :: _Platform_Error.EIO +ENXIO :: _Platform_Error.ENXIO +E2BIG :: _Platform_Error.E2BIG +ENOEXEC :: _Platform_Error.ENOEXEC +EBADF :: _Platform_Error.EBADF +ECHILD :: _Platform_Error.ECHILD +EDEADLK :: _Platform_Error.EDEADLK +ENOMEM :: _Platform_Error.ENOMEM +EACCES :: _Platform_Error.EACCES +EFAULT :: _Platform_Error.EFAULT +ENOTBLK :: _Platform_Error.ENOTBLK +EBUSY :: _Platform_Error.EBUSY +EEXIST :: _Platform_Error.EEXIST +EXDEV :: _Platform_Error.EXDEV +ENODEV :: _Platform_Error.ENODEV +ENOTDIR :: _Platform_Error.ENOTDIR +EISDIR :: _Platform_Error.EISDIR +EINVAL :: _Platform_Error.EINVAL +ENFILE :: _Platform_Error.ENFILE +EMFILE :: _Platform_Error.EMFILE +ENOTTY :: _Platform_Error.ENOTTY +ETXTBSY :: _Platform_Error.ETXTBSY +EFBIG :: _Platform_Error.EFBIG +ENOSPC :: _Platform_Error.ENOSPC +ESPIPE :: _Platform_Error.ESPIPE +EROFS :: _Platform_Error.EROFS +EMLINK :: _Platform_Error.EMLINK +EPIPE :: _Platform_Error.EPIPE + +/* math software */ +EDOM :: _Platform_Error.EDOM +ERANGE :: _Platform_Error.ERANGE + +/* non-blocking and interrupt i/o */ +EAGAIN :: _Platform_Error.EAGAIN +EWOULDBLOCK :: _Platform_Error.EWOULDBLOCK +EINPROGRESS :: _Platform_Error.EINPROGRESS +EALREADY :: _Platform_Error.EALREADY + +/* ipc/network software -- argument errors */ +ENOTSOCK :: _Platform_Error.ENOTSOCK +EDESTADDRREQ :: _Platform_Error.EDESTADDRREQ +EMSGSIZE :: _Platform_Error.EMSGSIZE +EPROTOTYPE :: _Platform_Error.EPROTOTYPE +ENOPROTOOPT :: _Platform_Error.ENOPROTOOPT +EPROTONOSUPPORT :: _Platform_Error.EPROTONOSUPPORT +ESOCKTNOSUPPORT :: _Platform_Error.ESOCKTNOSUPPORT +ENOTSUP :: _Platform_Error.ENOTSUP +EOPNOTSUPP :: _Platform_Error.EOPNOTSUPP +EPFNOSUPPORT :: _Platform_Error.EPFNOSUPPORT +EAFNOSUPPORT :: _Platform_Error.EAFNOSUPPORT +EADDRINUSE :: _Platform_Error.EADDRINUSE +EADDRNOTAVAIL :: _Platform_Error.EADDRNOTAVAIL + +/* ipc/network software -- operational errors */ +ENETDOWN :: _Platform_Error.ENETDOWN +ENETUNREACH :: _Platform_Error.ENETUNREACH +ENETRESET :: _Platform_Error.ENETRESET +ECONNABORTED :: _Platform_Error.ECONNABORTED +ECONNRESET :: _Platform_Error.ECONNRESET +ENOBUFS :: _Platform_Error.ENOBUFS +EISCONN :: _Platform_Error.EISCONN +ENOTCONN :: _Platform_Error.ENOTCONN +ESHUTDOWN :: _Platform_Error.ESHUTDOWN +ETOOMANYREFS :: _Platform_Error.ETOOMANYREFS +ETIMEDOUT :: _Platform_Error.ETIMEDOUT +ECONNREFUSED :: _Platform_Error.ECONNREFUSED + +ELOOP :: _Platform_Error.ELOOP +ENAMETOOLONG :: _Platform_Error.ENAMETOOLONG + +/* should be rearranged */ +EHOSTDOWN :: _Platform_Error.EHOSTDOWN +EHOSTUNREACH :: _Platform_Error.EHOSTUNREACH +ENOTEMPTY :: _Platform_Error.ENOTEMPTY + +/* quotas & mush */ +EPROCLIM :: _Platform_Error.EPROCLIM +EUSERS :: _Platform_Error.EUSERS +EDQUOT :: _Platform_Error.EDQUOT + +/* Network File System */ +ESTALE :: _Platform_Error.ESTALE +EREMOTE :: _Platform_Error.EREMOTE +EBADRPC :: _Platform_Error.EBADRPC +ERPCMISMATCH :: _Platform_Error.ERPCMISMATCH +EPROGUNAVAIL :: _Platform_Error.EPROGUNAVAIL +EPROGMISMATCH :: _Platform_Error.EPROGMISMATCH +EPROCUNAVAIL :: _Platform_Error.EPROCUNAVAIL + +ENOLCK :: _Platform_Error.ENOLCK +ENOSYS :: _Platform_Error.ENOSYS + +EFTYPE :: _Platform_Error.EFTYPE +EAUTH :: _Platform_Error.EAUTH +ENEEDAUTH :: _Platform_Error.ENEEDAUTH + +/* Intelligent device errors */ +EPWROFF :: _Platform_Error.EPWROFF +EDEVERR :: _Platform_Error.EDEVERR +EOVERFLOW :: _Platform_Error.EOVERFLOW + +/* Program loading errors */ +EBADEXEC :: _Platform_Error.EBADEXEC +EBADARCH :: _Platform_Error.EBADARCH +ESHLIBVERS :: _Platform_Error.ESHLIBVERS +EBADMACHO :: _Platform_Error.EBADMACHO + +ECANCELED :: _Platform_Error.ECANCELED + +EIDRM :: _Platform_Error.EIDRM +ENOMSG :: _Platform_Error.ENOMSG +EILSEQ :: _Platform_Error.EILSEQ +ENOATTR :: _Platform_Error.ENOATTR + +EBADMSG :: _Platform_Error.EBADMSG +EMULTIHOP :: _Platform_Error.EMULTIHOP +ENODATA :: _Platform_Error.ENODATA +ENOLINK :: _Platform_Error.ENOLINK +ENOSR :: _Platform_Error.ENOSR +ENOSTR :: _Platform_Error.ENOSTR +EPROTO :: _Platform_Error.EPROTO +ETIME :: _Platform_Error.ETIME + +ENOPOLICY :: _Platform_Error.ENOPOLICY + +ENOTRECOVERABLE :: _Platform_Error.ENOTRECOVERABLE +EOWNERDEAD :: _Platform_Error.EOWNERDEAD + +EQFULL :: _Platform_Error.EQFULL +ELAST :: _Platform_Error.ELAST -EPERM :: Platform_Error.EPERM -ENOENT :: Platform_Error.ENOENT -ESRCH :: Platform_Error.ESRCH -EINTR :: Platform_Error.EINTR -EIO :: Platform_Error.EIO -ENXIO :: Platform_Error.ENXIO -E2BIG :: Platform_Error.E2BIG -ENOEXEC :: Platform_Error.ENOEXEC -EBADF :: Platform_Error.EBADF -ECHILD :: Platform_Error.ECHILD -EDEADLK :: Platform_Error.EDEADLK -ENOMEM :: Platform_Error.ENOMEM -EACCES :: Platform_Error.EACCES -EFAULT :: Platform_Error.EFAULT -ENOTBLK :: Platform_Error.ENOTBLK -EBUSY :: Platform_Error.EBUSY -EEXIST :: Platform_Error.EEXIST -EXDEV :: Platform_Error.EXDEV -ENODEV :: Platform_Error.ENODEV -ENOTDIR :: Platform_Error.ENOTDIR -EISDIR :: Platform_Error.EISDIR -EINVAL :: Platform_Error.EINVAL -ENFILE :: Platform_Error.ENFILE -EMFILE :: Platform_Error.EMFILE -ENOTTY :: Platform_Error.ENOTTY -ETXTBSY :: Platform_Error.ETXTBSY -EFBIG :: Platform_Error.EFBIG -ENOSPC :: Platform_Error.ENOSPC -ESPIPE :: Platform_Error.ESPIPE -EROFS :: Platform_Error.EROFS -EMLINK :: Platform_Error.EMLINK -EPIPE :: Platform_Error.EPIPE -EDOM :: Platform_Error.EDOM -ERANGE :: Platform_Error.ERANGE -EAGAIN :: Platform_Error.EAGAIN -EWOULDBLOCK :: Platform_Error.EWOULDBLOCK -EINPROGRESS :: Platform_Error.EINPROGRESS -EALREADY :: Platform_Error.EALREADY -ENOTSOCK :: Platform_Error.ENOTSOCK -EDESTADDRREQ :: Platform_Error.EDESTADDRREQ -EMSGSIZE :: Platform_Error.EMSGSIZE -EPROTOTYPE :: Platform_Error.EPROTOTYPE -ENOPROTOOPT :: Platform_Error.ENOPROTOOPT -EPROTONOSUPPOR :: Platform_Error.EPROTONOSUPPOR -ESOCKTNOSUPPOR :: Platform_Error.ESOCKTNOSUPPOR -ENOTSUP :: Platform_Error.ENOTSUP -EOPNOTSUPP :: Platform_Error.EOPNOTSUPP -EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT -EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT -EADDRINUSE :: Platform_Error.EADDRINUSE -EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL -ENETDOWN :: Platform_Error.ENETDOWN -ENETUNREAC :: Platform_Error.ENETUNREAC -ENETRESET :: Platform_Error.ENETRESET -ECONNABORTE :: Platform_Error.ECONNABORTE -ECONNRESET :: Platform_Error.ECONNRESET -ENOBUFS :: Platform_Error.ENOBUFS -EISCONN :: Platform_Error.EISCONN -ENOTCONN :: Platform_Error.ENOTCONN -ESHUTDOWN :: Platform_Error.ESHUTDOWN -ETOOMANYREF :: Platform_Error.ETOOMANYREF -ETIMEDOUT :: Platform_Error.ETIMEDOUT -ECONNREFUSE :: Platform_Error.ECONNREFUSE -ELOOP :: Platform_Error.ELOOP -ENAMETOOLON :: Platform_Error.ENAMETOOLON -EHOSTDOWN :: Platform_Error.EHOSTDOWN -EHOSTUNREAC :: Platform_Error.EHOSTUNREAC -ENOTEMPTY :: Platform_Error.ENOTEMPTY -EPROCLIM :: Platform_Error.EPROCLIM -EUSERS :: Platform_Error.EUSERS -EDQUOT :: Platform_Error.EDQUOT -ESTALE :: Platform_Error.ESTALE -EREMOTE :: Platform_Error.EREMOTE -EBADRPC :: Platform_Error.EBADRPC -ERPCMISMATC :: Platform_Error.ERPCMISMATC -EPROGUNAVAI :: Platform_Error.EPROGUNAVAI -EPROGMISMATC :: Platform_Error.EPROGMISMATC -EPROCUNAVAI :: Platform_Error.EPROCUNAVAI -ENOLC :: Platform_Error.ENOLC -ENOSY :: Platform_Error.ENOSY -EFTYP :: Platform_Error.EFTYP -EAUT :: Platform_Error.EAUT -ENEEDAUT :: Platform_Error.ENEEDAUT -EPWROF :: Platform_Error.EPWROF -EDEVER :: Platform_Error.EDEVER -EOVERFLO :: Platform_Error.EOVERFLO -EBADEXE :: Platform_Error.EBADEXE -EBADARC :: Platform_Error.EBADARC -ESHLIBVER :: Platform_Error.ESHLIBVER -EBADMACH :: Platform_Error.EBADMACH -ECANCELE :: Platform_Error.ECANCELE -EIDRM :: Platform_Error.EIDRM -ENOMSG :: Platform_Error.ENOMSG -EILSEQ :: Platform_Error.EILSEQ -ENOATT :: Platform_Error.ENOATT -EBADMS :: Platform_Error.EBADMS -EMULTIHO :: Platform_Error.EMULTIHO -ENODAT :: Platform_Error.ENODAT -ENOLIN :: Platform_Error.ENOLIN -ENOSR :: Platform_Error.ENOSR -ENOSTR :: Platform_Error.ENOSTR -EPROTO :: Platform_Error.EPROTO -ETIME :: Platform_Error.ETIME -ENOPOLIC :: Platform_Error.ENOPOLIC -ENOTRECOVERABL :: Platform_Error.ENOTRECOVERABL -EOWNERDEAD :: Platform_Error.EOWNERDEAD -EQFUL :: Platform_Error.EQFUL -ELAS :: Platform_Error.ELAS O_RDONLY :: 0x0000 O_WRONLY :: 0x0001 From 5f7fef92fa0b901f21c442e7996c2cb8e2f3de78 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 12:25:50 +0100 Subject: [PATCH 069/122] Update example to use `err != nil` instead --- core/encoding/csv/example.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/encoding/csv/example.odin b/core/encoding/csv/example.odin index 24722589d..d791eb33b 100644 --- a/core/encoding/csv/example.odin +++ b/core/encoding/csv/example.odin @@ -38,9 +38,9 @@ iterate_csv_from_stream :: proc(filename: string) { r.reuse_record_buffer = true // Without it you have to each of the fields within it defer csv.reader_destroy(&r) - handle, errno := os.open(filename) - if errno != os.ERROR_NONE { - fmt.printfln("Error opening file: %v", filename) + handle, err := os.open(filename) + if err != nil { + fmt.eprintfln("Error opening file: %v", filename) return } defer os.close(handle) From e8b6d15db94b1f5d7be0c4c40d9a7f97898bcc94 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 12:31:22 +0100 Subject: [PATCH 070/122] Fix replace typo --- core/os/os_netbsd.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index d99a31f0a..d40f77416 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -421,7 +421,7 @@ W_OK :: 2 // Test for write permission R_OK :: 4 // Test for read permission foreign libc { - @(link_name="__Error") __Error_location :: proc() -> ^c.int --- + @(link_name="__error") __error_location :: proc() -> ^c.int --- @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- @@ -480,7 +480,7 @@ is_path_separator :: proc(r: rune) -> bool { @(require_results, no_instrumentation) get_last_error :: proc "contextless" () -> Error { - return Platform_Error(__Error_location()^) + return Platform_Error(__error_location()^) } @(require_results) From bdbbbf5c95b30bdb02f20399ffee1f3a19b0cf0c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 12:39:21 +0100 Subject: [PATCH 071/122] Fix typo; remove unneeded casts --- core/os/os_darwin.odin | 62 ++++++++++++++++++++--------------------- core/os/os_freebsd.odin | 42 ++++++++++++++-------------- core/os/os_haiku.odin | 30 ++++++++++---------- core/os/os_linux.odin | 14 +++++----- core/os/os_netbsd.odin | 46 +++++++++++++++--------------- core/os/os_openbsd.odin | 42 ++++++++++++++-------------- 6 files changed, 118 insertions(+), 118 deletions(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 420b8678d..4a317eddf 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -733,7 +733,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { bytes_written := _unix_write(fd, raw_data(data), to_write) if bytes_written < 0 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return bytes_written, nil } @@ -747,7 +747,7 @@ read :: proc(fd: Handle, data: []u8) -> (int, Error) { bytes_read := _unix_read(fd, raw_data(data), to_read) if bytes_read < 0 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return bytes_read, nil } @@ -761,7 +761,7 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) { bytes_read := _unix_pread(fd, raw_data(data), to_read, offset) if bytes_read < 0 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return bytes_read, nil } @@ -775,7 +775,7 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) { bytes_written := _unix_pwrite(fd, raw_data(data), to_write, offset) if bytes_written < 0 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return bytes_written, nil } @@ -888,7 +888,7 @@ remove :: proc(path: string) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_remove(path_cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -901,7 +901,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { s: OS_Stat result := _unix_stat(cstr, &s) if result == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -914,7 +914,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { s: OS_Stat result := _unix_lstat(cstr, &s) if result == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -924,7 +924,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat result := _unix_fstat(fd, &s) if result == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -933,7 +933,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Error(get_last_error()) + return nil, get_last_error() } return dirp, nil } @@ -942,7 +942,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -958,7 +958,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Error(get_last_error()) + err = get_last_error() return } @@ -982,7 +982,7 @@ _readlink :: proc(path: string) -> (string, Error) { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) if rc == -1 { delete(buf) - return "", Error(get_last_error()) + return "", get_last_error() } else if rc == int(bufsz) { // NOTE(laleksic, 2021-01-21): Any cleaner way to resize the slice? bufsz *= 2 @@ -1011,7 +1011,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Error(get_last_error()) + return "", get_last_error() } defer _unix_free(path_ptr) @@ -1052,7 +1052,7 @@ set_env :: proc(key, value: string) -> Error { value_cstring := strings.clone_to_cstring(value, context.temp_allocator) res := _unix_setenv(key_cstring, value_cstring, 1) if res < 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -1062,7 +1062,7 @@ unset_env :: proc(key: string) -> Error { s := strings.clone_to_cstring(key, context.temp_allocator) res := _unix_unsetenv(s) if res < 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -1075,7 +1075,7 @@ get_current_directory :: proc() -> string { if cwd != nil { return string(cwd) } - if Error(get_last_error()) != ERANGE { + if get_last_error() != ERANGE { delete(buf) return "" } @@ -1089,7 +1089,7 @@ set_current_directory :: proc(path: string) -> (err: Error) { cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -1099,7 +1099,7 @@ make_directory :: proc(path: string, mode: u16 = 0o775) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -1176,7 +1176,7 @@ _alloc_command_line_arguments :: proc() -> []string { socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { result := _unix_socket(domain, type, protocol) if result < 0 { - return 0, Error(get_last_error()) + return 0, get_last_error() } return Socket(result), nil } @@ -1184,7 +1184,7 @@ socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { result := _unix_connect(int(sd), addr, len) if result < 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -1192,7 +1192,7 @@ connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { result := _unix_bind(int(sd), addr, len) if result < 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -1200,7 +1200,7 @@ bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Error) { result := _unix_accept(int(sd), rawptr(addr), len) if result < 0 { - return 0, Error(get_last_error()) + return 0, get_last_error() } return Socket(result), nil } @@ -1208,7 +1208,7 @@ accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Error) { listen :: proc(sd: Socket, backlog: int) -> (Error) { result := _unix_listen(int(sd), backlog) if result < 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -1216,7 +1216,7 @@ listen :: proc(sd: Socket, backlog: int) -> (Error) { setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> (Error) { result := _unix_setsockopt(int(sd), level, optname, optval, optlen) if result < 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -1224,7 +1224,7 @@ setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Error { result := _unix_getsockopt(int(sd), level, optname, optval, optlen) if result < 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -1232,7 +1232,7 @@ getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Error) { result := _unix_recvfrom(int(sd), raw_data(data), len(data), flags, addr, addr_size) if result < 0 { - return 0, Error(get_last_error()) + return 0, get_last_error() } return u32(result), nil } @@ -1240,7 +1240,7 @@ recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_siz recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { result := _unix_recv(int(sd), raw_data(data), len(data), flags) if result < 0 { - return 0, Error(get_last_error()) + return 0, get_last_error() } return u32(result), nil } @@ -1248,7 +1248,7 @@ recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: socklen_t) -> (u32, Error) { result := _unix_sendto(int(sd), raw_data(data), len(data), flags, addr, addrlen) if result < 0 { - return 0, Error(get_last_error()) + return 0, get_last_error() } return u32(result), nil } @@ -1256,7 +1256,7 @@ sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: soc send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { result := _unix_send(int(sd), raw_data(data), len(data), 0) if result < 0 { - return 0, Error(get_last_error()) + return 0, get_last_error() } return u32(result), nil } @@ -1264,7 +1264,7 @@ send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { shutdown :: proc(sd: Socket, how: int) -> (Error) { result := _unix_shutdown(int(sd), how) if result < 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -1272,7 +1272,7 @@ shutdown :: proc(sd: Socket, how: int) -> (Error) { fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Error) { result := _unix__fcntl(Handle(fd), c.int(cmd), uintptr(arg)) if result < 0 { - return 0, Error(get_last_error()) + return 0, get_last_error() } return int(result), nil } diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 3f65e393b..7840a72ea 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -429,7 +429,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { - return INVALID_HANDLE, Error(get_last_error()) + return INVALID_HANDLE, get_last_error() } return handle, nil } @@ -437,7 +437,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err close :: proc(fd: Handle) -> Error { result := _unix_close(fd) if result == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -454,7 +454,7 @@ read :: proc(fd: Handle, data: []byte) -> (int, Error) { to_read := min(c.size_t(len(data)), MAX_RW) bytes_read := _unix_read(fd, &data[0], to_read) if bytes_read == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return int(bytes_read), nil } @@ -467,7 +467,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { to_write := min(c.size_t(len(data)), MAX_RW) bytes_written := _unix_write(fd, &data[0], to_write) if bytes_written == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return int(bytes_written), nil } @@ -475,7 +475,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return res, nil } @@ -493,7 +493,7 @@ rename :: proc(old_path, new_path: string) -> Error { new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) res := _unix_rename(old_path_cstr, new_path_cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -503,7 +503,7 @@ remove :: proc(path: string) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_unlink(path_cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -513,7 +513,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -523,7 +523,7 @@ remove_directory :: proc(path: string) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_rmdir(path_cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -610,7 +610,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { s: OS_Stat = --- result := _unix_lstat(cstr, &s) if result == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -624,7 +624,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { s: OS_Stat = --- res := _unix_lstat(cstr, &s) if res == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -634,7 +634,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat = --- result := _unix_fstat(fd, &s) if result == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -643,7 +643,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Error(get_last_error()) + return nil, get_last_error() } return dirp, nil } @@ -652,7 +652,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -668,7 +668,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Error(get_last_error()) + err = get_last_error() return } @@ -692,7 +692,7 @@ _readlink :: proc(path: string) -> (string, Error) { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) if rc == -1 { delete(buf) - return "", Error(get_last_error()) + return "", get_last_error() } else if rc == int(bufsz) { bufsz += MAX_PATH delete(buf) @@ -720,7 +720,7 @@ absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { res := _unix_fcntl(fd, F_KINFO, cast(uintptr)&kinfo) if res == -1 { - return "", Error(get_last_error()) + return "", get_last_error() } path := strings.clone_from_cstring_bounded(cast(cstring)&kinfo.path[0], len(kinfo.path)) @@ -738,7 +738,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Error(get_last_error()) + return "", get_last_error() } defer _unix_free(path_ptr) @@ -754,7 +754,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) { cstr := strings.clone_to_cstring(path, context.temp_allocator) result := _unix_access(cstr, c.int(mask)) if result == -1 { - return false, Error(get_last_error()) + return false, get_last_error() } return true, nil } @@ -786,7 +786,7 @@ get_current_directory :: proc() -> string { if cwd != nil { return string(cwd) } - if Error(get_last_error()) != ERANGE { + if get_last_error() != ERANGE { delete(buf) return "" } @@ -800,7 +800,7 @@ set_current_directory :: proc(path: string) -> (err: Error) { cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index d7a5c5db8..bd5e945d0 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -189,7 +189,7 @@ get_last_error :: proc "contextless" () -> Error { fork :: proc() -> (Pid, Error) { pid := _unix_fork() if pid == -1 { - return Pid(-1), Error(get_last_error()) + return Pid(-1), get_last_error() } return Pid(pid), nil } @@ -199,7 +199,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { - return INVALID_HANDLE, Error(get_last_error()) + return INVALID_HANDLE, get_last_error() } return handle, nil } @@ -207,7 +207,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err close :: proc(fd: Handle) -> Error { result := _unix_close(fd) if result == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -223,7 +223,7 @@ read :: proc(fd: Handle, data: []byte) -> (int, Error) { to_read := min(c.size_t(len(data)), MAX_RW) bytes_read := _unix_read(fd, &data[0], to_read) if bytes_read == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return int(bytes_read), nil } @@ -236,7 +236,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { to_write := min(c.size_t(len(data)), MAX_RW) bytes_written := _unix_write(fd, &data[0], to_write) if bytes_written == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return int(bytes_written), nil } @@ -244,7 +244,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return res, nil } @@ -277,7 +277,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { s: OS_Stat = --- res := _unix_stat(cstr, &s) if res == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -291,7 +291,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { s: OS_Stat = --- res := _unix_lstat(cstr, &s) if res == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -302,7 +302,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat = --- res := _unix_fstat(fd, &s) if res == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -311,7 +311,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Error(get_last_error()) + return nil, get_last_error() } return dirp, nil } @@ -320,7 +320,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -336,7 +336,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Error(get_last_error()) + err = get_last_error() return } @@ -359,7 +359,7 @@ _readlink :: proc(path: string) -> (string, Error) { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) if rc == -1 { delete(buf) - return "", Error(get_last_error()) + return "", get_last_error() } else if rc == int(bufsz) { bufsz += MAX_PATH delete(buf) @@ -385,7 +385,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Error(get_last_error()) + return "", get_last_error() } defer _unix_free(path_ptr) @@ -400,7 +400,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) { cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_access(cstr, c.int(mask)) if res == -1 { - return false, Error(get_last_error()) + return false, get_last_error() } return true, nil } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 42a10a874..267ba3330 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -563,7 +563,7 @@ execvp :: proc(path: string, args: []string) -> Error { } _unix_execvp(path_cstr, raw_data(args_cstrs)) - return Error(get_last_error()) + return get_last_error() } @@ -809,7 +809,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Error(get_last_error()) + return nil, get_last_error() } return dirp, nil } @@ -818,7 +818,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -834,7 +834,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Error(get_last_error()) + err = get_last_error() return } err = nil @@ -892,7 +892,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Error(get_last_error()) + return "", get_last_error() } defer _unix_free(path_ptr) @@ -934,7 +934,7 @@ set_env :: proc(key, value: string) -> Error { // NOTE(GoNZooo): `setenv` instead of `putenv` because it copies both key and value more commonly res := _unix_setenv(key_cstring, value_cstring, 1) if res < 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -944,7 +944,7 @@ unset_env :: proc(key: string) -> Error { s := strings.clone_to_cstring(key, context.temp_allocator) res := _unix_putenv(s) if res < 0 { - return Error(get_last_error()) + return get_last_error() } return nil } diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index d40f77416..4d35a691e 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -421,7 +421,7 @@ W_OK :: 2 // Test for write permission R_OK :: 4 // Test for read permission foreign libc { - @(link_name="__error") __error_location :: proc() -> ^c.int --- + @(link_name="__errno") __errno_location :: proc() -> ^c.int --- @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- @@ -480,7 +480,7 @@ is_path_separator :: proc(r: rune) -> bool { @(require_results, no_instrumentation) get_last_error :: proc "contextless" () -> Error { - return Platform_Error(__error_location()^) + return Platform_Error(__errno_location()^) } @(require_results) @@ -489,7 +489,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { - return INVALID_HANDLE, Error(get_last_error()) + return INVALID_HANDLE, get_last_error() } return handle, nil } @@ -497,7 +497,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err close :: proc(fd: Handle) -> Error { result := _unix_close(fd) if result == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -510,7 +510,7 @@ read :: proc(fd: Handle, data: []byte) -> (int, Error) { to_read := min(c.size_t(len(data)), MAX_RW) bytes_read := _unix_read(fd, &data[0], to_read) if bytes_read == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return int(bytes_read), nil } @@ -523,7 +523,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { to_write := min(c.size_t(len(data)), MAX_RW) bytes_written := _unix_write(fd, &data[0], to_write) if bytes_written == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return int(bytes_written), nil } @@ -531,7 +531,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return res, nil } @@ -549,7 +549,7 @@ rename :: proc(old_path, new_path: string) -> Error { new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) res := _unix_rename(old_path_cstr, new_path_cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -559,7 +559,7 @@ remove :: proc(path: string) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_unlink(path_cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -569,7 +569,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -579,7 +579,7 @@ remove_directory :: proc(path: string) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_rmdir(path_cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -641,7 +641,7 @@ exists :: proc(path: string) -> bool { fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Error) { result := _unix_fcntl(Handle(fd), c.int(cmd), uintptr(arg)) if result < 0 { - return 0, Error(get_last_error()) + return 0, get_last_error() } return int(result), nil } @@ -671,7 +671,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { s: OS_Stat = --- result := _unix_lstat(cstr, &s) if result == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -685,7 +685,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { s: OS_Stat = --- res := _unix_lstat(cstr, &s) if res == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -695,7 +695,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat = --- result := _unix_fstat(fd, &s) if result == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -704,7 +704,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Error(get_last_error()) + return nil, get_last_error() } return dirp, nil } @@ -713,7 +713,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -729,7 +729,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Error(get_last_error()) + err = get_last_error() return } err = nil @@ -754,7 +754,7 @@ _readlink :: proc(path: string) -> (string, Error) { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) if rc == -1 { delete(buf) - return "", Error(get_last_error()) + return "", get_last_error() } else if rc == int(bufsz) { bufsz += MAX_PATH delete(buf) @@ -784,7 +784,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Error(get_last_error()) + return "", get_last_error() } defer _unix_free(path_ptr) @@ -799,7 +799,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) { cstr := strings.clone_to_cstring(path, context.temp_allocator) result := _unix_access(cstr, c.int(mask)) if result == -1 { - return false, Error(get_last_error()) + return false, get_last_error() } return true, nil } @@ -831,7 +831,7 @@ get_current_directory :: proc() -> string { if cwd != nil { return string(cwd) } - if Error(get_last_error()) != ERANGE { + if get_last_error() != ERANGE { delete(buf) return "" } @@ -845,7 +845,7 @@ set_current_directory :: proc(path: string) -> (err: Error) { cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 1309d0c0d..f8d468b6d 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -402,7 +402,7 @@ get_last_error :: proc "contextless" () -> Error { fork :: proc() -> (Pid, Error) { pid := _unix_fork() if pid == -1 { - return Pid(-1), Error(get_last_error()) + return Pid(-1), get_last_error() } return Pid(pid), nil } @@ -413,7 +413,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { - return INVALID_HANDLE, Error(get_last_error()) + return INVALID_HANDLE, get_last_error() } return handle, nil } @@ -421,7 +421,7 @@ open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Err close :: proc(fd: Handle) -> Error { result := _unix_close(fd) if result == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -438,7 +438,7 @@ read :: proc(fd: Handle, data: []byte) -> (int, Error) { to_read := min(c.size_t(len(data)), MAX_RW) bytes_read := _unix_read(fd, &data[0], to_read) if bytes_read == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return int(bytes_read), nil } @@ -451,7 +451,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { to_write := min(c.size_t(len(data)), MAX_RW) bytes_written := _unix_write(fd, &data[0], to_write) if bytes_written == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return int(bytes_written), nil } @@ -459,7 +459,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { - return -1, Error(get_last_error()) + return -1, get_last_error() } return res, nil } @@ -477,7 +477,7 @@ rename :: proc(old_path, new_path: string) -> Error { new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) res := _unix_rename(old_path_cstr, new_path_cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -487,7 +487,7 @@ remove :: proc(path: string) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_unlink(path_cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -497,7 +497,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -507,7 +507,7 @@ remove_directory :: proc(path: string) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_rmdir(path_cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -590,7 +590,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { s: OS_Stat = --- res := _unix_stat(cstr, &s) if res == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -604,7 +604,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { s: OS_Stat = --- res := _unix_lstat(cstr, &s) if res == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -615,7 +615,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat = --- res := _unix_fstat(fd, &s) if res == -1 { - return s, Error(get_last_error()) + return s, get_last_error() } return s, nil } @@ -624,7 +624,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { - return nil, Error(get_last_error()) + return nil, get_last_error() } return dirp, nil } @@ -633,7 +633,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { - return Error(get_last_error()) + return get_last_error() } return nil } @@ -649,7 +649,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) rc := _unix_readdir_r(dirp, &entry, &result) if rc != 0 { - err = Error(get_last_error()) + err = get_last_error() return } err = nil @@ -673,7 +673,7 @@ _readlink :: proc(path: string) -> (string, Error) { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) if rc == -1 { delete(buf) - return "", Error(get_last_error()) + return "", get_last_error() } else if rc == int(bufsz) { bufsz += MAX_PATH delete(buf) @@ -700,7 +700,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { - return "", Error(get_last_error()) + return "", get_last_error() } defer _unix_free(path_ptr) @@ -714,7 +714,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) { cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_access(cstr, c.int(mask)) if res == -1 { - return false, Error(get_last_error()) + return false, get_last_error() } return true, nil } @@ -741,7 +741,7 @@ get_current_directory :: proc() -> string { if cwd != nil { return string(cwd) } - if Error(get_last_error()) != ERANGE { + if get_last_error() != ERANGE { delete(buf) return "" } @@ -755,7 +755,7 @@ set_current_directory :: proc(path: string) -> (err: Error) { cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 { - return Error(get_last_error()) + return get_last_error() } return nil } From 649b25fba6d04dd4e99d0e8bc6b7f2543d09ad7e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 12:47:49 +0100 Subject: [PATCH 072/122] Update the `demo.odin` to use `nil` instead of `os.ERROR_NONE` --- examples/demo/demo.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index d31711bad..d66d1ceb0 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -359,7 +359,7 @@ control_flow :: proc() { if false { f, err := os.open("my_file.txt") - if err != os.ERROR_NONE { + if err != nil { // handle error } defer os.close(f) From c32f345c68fa42232d0b1f437872514a695fea0a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 12:55:08 +0100 Subject: [PATCH 073/122] Move error stuff to `errors.odin` --- core/os/errors.odin | 159 ++++++++++++++++++++++++++++++++++++++++++++ core/os/os.odin | 49 -------------- 2 files changed, 159 insertions(+), 49 deletions(-) create mode 100644 core/os/errors.odin diff --git a/core/os/errors.odin b/core/os/errors.odin new file mode 100644 index 000000000..63b0145e0 --- /dev/null +++ b/core/os/errors.odin @@ -0,0 +1,159 @@ +package os + +import "base:intrinsics" +import "base:runtime" +import "core:io" + +Platform_Error :: _Platform_Error +#assert(size_of(Platform_Error) <= 4) +#assert(intrinsics.type_has_nil(Platform_Error)) + +General_Error :: enum u32 { + None, + + Permission_Denied, + Exist, + Not_Exist, + Closed, + + Timeout, + + Broken_Pipe, + + // Indicates that an attempt to retrieve a file's size was made, but the + // file doesn't have a size. + No_Size, + + Invalid_File, + Invalid_Dir, + Invalid_Path, + Invalid_Callback, + + Pattern_Has_Separator, + + Unsupported, +} + + +Errno :: Error // alias for legacy use + +Error :: union #shared_nil { + General_Error, + io.Error, + runtime.Allocator_Error, + Platform_Error, +} +#assert(size_of(Error) == 8) + +ERROR_NONE :: Error{} + +@(require_results) +is_platform_error :: proc "contextless" (ferr: Error) -> (err: i32, ok: bool) { + v := ferr.(Platform_Error) or_else {} + return i32(v), i32(v) != 0 +} + +@(require_results) +error_string :: proc "contextless" (ferr: Error) -> string { + if ferr == nil { + return "" + } + switch e in ferr { + case General_Error: + switch e { + case .None: return "" + case .Permission_Denied: return "permission denied" + case .Exist: return "file already exists" + case .Not_Exist: return "file does not exist" + case .Closed: return "file already closed" + case .Timeout: return "i/o timeout" + case .Broken_Pipe: return "Broken pipe" + case .No_Size: return "file has no definite size" + case .Invalid_File: return "invalid file" + case .Invalid_Dir: return "invalid directory" + case .Invalid_Path: return "invalid path" + case .Invalid_Callback: return "invalid callback" + case .Unsupported: return "unsupported" + case .Pattern_Has_Separator: return "pattern has separator" + } + case io.Error: + switch e { + case .None: return "" + case .EOF: return "eof" + case .Unexpected_EOF: return "unexpected eof" + case .Short_Write: return "short write" + case .Invalid_Write: return "invalid write result" + case .Short_Buffer: return "short buffer" + case .No_Progress: return "multiple read calls return no data or error" + case .Invalid_Whence: return "invalid whence" + case .Invalid_Offset: return "invalid offset" + case .Invalid_Unread: return "invalid unread" + case .Negative_Read: return "negative read" + case .Negative_Write: return "negative write" + case .Negative_Count: return "negative count" + case .Buffer_Full: return "buffer full" + case .Unknown, .Empty: // + } + case runtime.Allocator_Error: + switch e { + case .None: return "" + case .Out_Of_Memory: return "out of memory" + case .Invalid_Pointer: return "invalid allocator pointer" + case .Invalid_Argument: return "invalid allocator argument" + case .Mode_Not_Implemented: return "allocator mode not implemented" + } + case Platform_Error: + return _error_string(e) + } + + return "unknown error" +} + +print_error :: proc(f: Handle, ferr: Error, msg: string) -> (n: int, err: Error) { + err_str := error_string(ferr) + + // msg + ": " + err_str + '\n' + length := len(msg) + 2 + len(err_str) + 1 + buf_ := intrinsics.alloca(length, 1) + buf := buf_[:length] + + copy(buf, msg) + buf[len(msg)] = ':' + buf[len(msg) + 1] = ' ' + copy(buf[len(msg) + 2:], err_str) + buf[length - 1] = '\n' + return write(f, buf) +} + + +@(require_results, private) +_error_string :: proc "contextless" (e: Platform_Error) -> string where intrinsics.type_is_enum(Platform_Error) { + @(require_results) + binary_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) #no_bounds_check { + n := len(array) + left, right := 0, n + for left < right { + mid := int(uint(left+right) >> 1) + if array[mid] < key { + left = mid+1 + } else { + // equal or greater + right = mid + } + } + return left, left < n && array[left] == key + } + + + if e == nil { + return "" + } + + err := runtime.Type_Info_Enum_Value(e) + + ti := &runtime.type_info_base(type_info_of(Platform_Error)).variant.(runtime.Type_Info_Enum) + if idx, ok := binary_search(ti.values, err); ok { + return ti.names[idx] + } + return "" +} \ No newline at end of file diff --git a/core/os/os.odin b/core/os/os.odin index e383b779d..51bb4b88e 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -15,55 +15,6 @@ SEEK_SET :: 0 SEEK_CUR :: 1 SEEK_END :: 2 -Platform_Error :: _Platform_Error -#assert(size_of(Platform_Error) <= 4) -#assert(intrinsics.type_has_nil(Platform_Error)) - -General_Error :: enum u32 { - None, - - Permission_Denied, - Exist, - Not_Exist, - Closed, - - Timeout, - - Broken_Pipe, - - // Indicates that an attempt to retrieve a file's size was made, but the - // file doesn't have a size. - No_Size, - - Invalid_File, - Invalid_Dir, - Invalid_Path, - Invalid_Callback, - - Pattern_Has_Separator, - - Unsupported, -} - - -Errno :: Error // alias for legacy use - -Error :: union #shared_nil { - General_Error, - io.Error, - runtime.Allocator_Error, - Platform_Error, -} -#assert(size_of(Error) == 8) - -ERROR_NONE :: Error{} - -@(require_results) -is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { - v := ferr.(Platform_Error) or_else {} - return i32(v), i32(v) != 0 -} - write_string :: proc(fd: Handle, str: string) -> (int, Error) { return write(fd, transmute([]byte)str) } From 7663a2036aa121900b6e13c60e1dd7f5297f4f5e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 13:15:58 +0100 Subject: [PATCH 074/122] Add read_at/write_at to missing platforms --- core/os/errors.odin | 10 +++++++++- core/os/os_freebsd.odin | 20 ++++++++++++++++++++ core/os/os_haiku.odin | 20 ++++++++++++++++++++ core/os/os_netbsd.odin | 20 ++++++++++++++++++++ core/os/os_openbsd.odin | 20 ++++++++++++++++++++ core/os/stream.odin | 28 ++++++++++------------------ 6 files changed, 99 insertions(+), 19 deletions(-) diff --git a/core/os/errors.odin b/core/os/errors.odin index 63b0145e0..347f314d3 100644 --- a/core/os/errors.odin +++ b/core/os/errors.odin @@ -156,4 +156,12 @@ _error_string :: proc "contextless" (e: Platform_Error) -> string where intrinsi return ti.names[idx] } return "" -} \ No newline at end of file +} + +@(private, require_results) +error_to_io_error :: proc(ferr: Error) -> io.Error { + if ferr == nil { + return .None + } + return ferr.(io.Error) or_else .Unknown +} diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 7840a72ea..3c514084e 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -472,6 +472,26 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { return int(bytes_written), nil } +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { + curr := seek(fd, offset, SEEK_CUR) or_return + n, err = read(fd, data) + _, err1 := seek(fd, curr, SEEK_SET) + if err1 != nil && err == nil { + err = err1 + } + return +} + +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { + curr := seek(fd, offset, SEEK_CUR) or_return + n, err = write(fd, data) + _, err1 := seek(fd, curr, SEEK_SET) + if err1 != nil && err == nil { + err = err1 + } + return +} + seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index bd5e945d0..ff06d2c80 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -241,6 +241,26 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { return int(bytes_written), nil } +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { + curr := seek(fd, offset, SEEK_CUR) or_return + n, err = read(fd, data) + _, err1 := seek(fd, curr, SEEK_SET) + if err1 != nil && err == nil { + err = err1 + } + return +} + +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { + curr := seek(fd, offset, SEEK_CUR) or_return + n, err = write(fd, data) + _, err1 := seek(fd, curr, SEEK_SET) + if err1 != nil && err == nil { + err = err1 + } + return +} + seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index 4d35a691e..69d0cab8a 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -528,6 +528,26 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { return int(bytes_written), nil } +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { + curr := seek(fd, offset, SEEK_CUR) or_return + n, err = read(fd, data) + _, err1 := seek(fd, curr, SEEK_SET) + if err1 != nil && err == nil { + err = err1 + } + return +} + +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { + curr := seek(fd, offset, SEEK_CUR) or_return + n, err = write(fd, data) + _, err1 := seek(fd, curr, SEEK_SET) + if err1 != nil && err == nil { + err = err1 + } + return +} + seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index f8d468b6d..30ffb3432 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -456,6 +456,26 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { return int(bytes_written), nil } +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { + curr := seek(fd, offset, SEEK_CUR) or_return + n, err = read(fd, data) + _, err1 := seek(fd, curr, SEEK_SET) + if err1 != nil && err == nil { + err = err1 + } + return +} + +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { + curr := seek(fd, offset, SEEK_CUR) or_return + n, err = write(fd, data) + _, err1 := seek(fd, curr, SEEK_SET) + if err1 != nil && err == nil { + err = err1 + } + return +} + seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { diff --git a/core/os/stream.odin b/core/os/stream.odin index c421285cd..7ec0e29a6 100644 --- a/core/os/stream.odin +++ b/core/os/stream.odin @@ -32,12 +32,10 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, } case .Read_At: - when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Haiku) { - n_int, os_err = read_at(fd, p, offset) - n = i64(n_int) - if n == 0 && os_err == nil { - err = .EOF - } + n_int, os_err = read_at(fd, p, offset) + n = i64(n_int) + if n == 0 && os_err == nil { + err = .EOF } case .Write: n_int, os_err = write(fd, p) @@ -46,12 +44,10 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, err = .EOF } case .Write_At: - when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Haiku) { - n_int, os_err = write_at(fd, p, offset) - n = i64(n_int) - if n == 0 && os_err == nil { - err = .EOF - } + n_int, os_err = write_at(fd, p, offset) + n = i64(n_int) + if n == 0 && os_err == nil { + err = .EOF } case .Seek: n, os_err = seek(fd, offset, int(whence)) @@ -60,11 +56,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, case .Destroy: err = .Empty case .Query: - when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Haiku { - return io.query_utility({.Close, .Flush, .Read, .Write, .Seek, .Size, .Query}) - } else { - return io.query_utility({.Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Query}) - } + return io.query_utility({.Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Query}) } if err == nil && os_err != nil { @@ -73,7 +65,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, return n, .EOF } } - err = .Unknown + err = error_to_io_error(os_err) } return } From cf5ec2587364f195b1e6562d84ddb4bc75e706a4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 13:18:51 +0100 Subject: [PATCH 075/122] Add extra cases for `flush` --- core/os/stream.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/stream.odin b/core/os/stream.odin index 7ec0e29a6..26bfee91d 100644 --- a/core/os/stream.odin +++ b/core/os/stream.odin @@ -19,7 +19,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, case .Close: close(fd) case .Flush: - when ODIN_OS == .Windows { + when ODIN_OS == .Windows || ODIN_OS == .Darwin || ODIN_OS == .JS { flush(fd) } else { // TOOD(bill): other operating systems From 0c5b645dde35e2cad729c7dd89fccaf22d56aa35 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 13:20:33 +0100 Subject: [PATCH 076/122] Correct `EOF` value --- core/os/file_windows.odin | 2 +- core/os/os_windows.odin | 2 +- core/os/stream.odin | 5 ----- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 54c456fb4..76f0f2c26 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -173,7 +173,7 @@ read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Error) { // Successful read can mean two things, including EOF, see: // https://learn.microsoft.com/en-us/windows/win32/fileio/testing-for-the-end-of-a-file if bytes_read == 0 { - return 0, ERROR_HANDLE_EOF + return 0, .EOF } else { return int(bytes_read), nil } diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 58f03f279..af5b485a6 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -35,7 +35,7 @@ ERROR_INVALID_HANDLE :: _Platform_Error(6) ERROR_NOT_ENOUGH_MEMORY :: _Platform_Error(8) ERROR_NO_MORE_FILES :: _Platform_Error(18) ERROR_HANDLE_EOF :: _Platform_Error(38) -ERROR_EOF :: ERROR_HANDLE_EOF +ERROR_EOF :: General_Error.EOF ERROR_NETNAME_DELETED :: _Platform_Error(64) ERROR_FILE_EXISTS :: _Platform_Error(80) ERROR_INVALID_PARAMETER :: _Platform_Error(87) diff --git a/core/os/stream.odin b/core/os/stream.odin index 26bfee91d..cb392ccaf 100644 --- a/core/os/stream.odin +++ b/core/os/stream.odin @@ -60,11 +60,6 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, } if err == nil && os_err != nil { - when ODIN_OS == .Windows { - if os_err == ERROR_HANDLE_EOF { - return n, .EOF - } - } err = error_to_io_error(os_err) } return From 3d992e2704511b77cb6c1187652c0952ea8d38f6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 13:25:35 +0100 Subject: [PATCH 077/122] Improve `_error_string` for Linux --- core/os/errors.odin | 186 ++++++++++++++++++++++++++++++---- core/os/os2/errors_linux.odin | 4 +- core/os/os_windows.odin | 1 - 3 files changed, 167 insertions(+), 24 deletions(-) diff --git a/core/os/errors.odin b/core/os/errors.odin index 347f314d3..c7fd12dfb 100644 --- a/core/os/errors.odin +++ b/core/os/errors.odin @@ -47,6 +47,8 @@ Error :: union #shared_nil { ERROR_NONE :: Error{} +ERROR_EOF :: io.Error.EOF + @(require_results) is_platform_error :: proc "contextless" (ferr: Error) -> (err: i32, ok: bool) { v := ferr.(Platform_Error) or_else {} @@ -128,32 +130,174 @@ print_error :: proc(f: Handle, ferr: Error, msg: string) -> (n: int, err: Error) @(require_results, private) _error_string :: proc "contextless" (e: Platform_Error) -> string where intrinsics.type_is_enum(Platform_Error) { - @(require_results) - binary_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) #no_bounds_check { - n := len(array) - left, right := 0, n - for left < right { - mid := int(uint(left+right) >> 1) - if array[mid] < key { - left = mid+1 - } else { - // equal or greater - right = mid - } - } - return left, left < n && array[left] == key - } - - if e == nil { return "" } - err := runtime.Type_Info_Enum_Value(e) + when ODIN_OS != .Linux { + @(require_results) + binary_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) #no_bounds_check { + n := len(array) + left, right := 0, n + for left < right { + mid := int(uint(left+right) >> 1) + if array[mid] < key { + left = mid+1 + } else { + // equal or greater + right = mid + } + } + return left, left < n && array[left] == key + } - ti := &runtime.type_info_base(type_info_of(Platform_Error)).variant.(runtime.Type_Info_Enum) - if idx, ok := binary_search(ti.values, err); ok { - return ti.names[idx] + err := runtime.Type_Info_Enum_Value(e) + + ti := &runtime.type_info_base(type_info_of(Platform_Error)).variant.(runtime.Type_Info_Enum) + if idx, ok := binary_search(ti.values, err); ok { + return ti.names[idx] + } + } else { + @(rodata, static) + pe_strings := [Platform_Error]string{ + .NONE = "", + .EPERM = "Operation not permitted", + .ENOENT = "No such file or directory", + .ESRCH = "No such process", + .EINTR = "Interrupted system call", + .EIO = "Input/output error", + .ENXIO = "No such device or address", + .E2BIG = "Argument list too long", + .ENOEXEC = "Exec format error", + .EBADF = "Bad file descriptor", + .ECHILD = "No child processes", + .EAGAIN = "Resource temporarily unavailable", + .ENOMEM = "Cannot allocate memory", + .EACCES = "Permission denied", + .EFAULT = "Bad address", + .ENOTBLK = "Block device required", + .EBUSY = "Device or resource busy", + .EEXIST = "File exists", + .EXDEV = "Invalid cross-device link", + .ENODEV = "No such device", + .ENOTDIR = "Not a directory", + .EISDIR = "Is a directory", + .EINVAL = "Invalid argument", + .ENFILE = "Too many open files in system", + .EMFILE = "Too many open files", + .ENOTTY = "Inappropriate ioctl for device", + .ETXTBSY = "Text file busy", + .EFBIG = "File too large", + .ENOSPC = "No space left on device", + .ESPIPE = "Illegal seek", + .EROFS = "Read-only file system", + .EMLINK = "Too many links", + .EPIPE = "Broken pipe", + .EDOM = "Numerical argument out of domain", + .ERANGE = "Numerical result out of range", + .EDEADLK = "Resource deadlock avoided", + .ENAMETOOLONG = "File name too long", + .ENOLCK = "No locks available", + .ENOSYS = "Function not implemented", + .ENOTEMPTY = "Directory not empty", + .ELOOP = "Too many levels of symbolic links", + .EUNKNOWN_41 = "Unknown Error (41)", + .ENOMSG = "No message of desired type", + .EIDRM = "Identifier removed", + .ECHRNG = "Channel number out of range", + .EL2NSYNC = "Level 2 not synchronized", + .EL3HLT = "Level 3 halted", + .EL3RST = "Level 3 reset", + .ELNRNG = "Link number out of range", + .EUNATCH = "Protocol driver not attached", + .ENOCSI = "No CSI structure available", + .EL2HLT = "Level 2 halted", + .EBADE = "Invalid exchange", + .EBADR = "Invalid request descriptor", + .EXFULL = "Exchange full", + .ENOANO = "No anode", + .EBADRQC = "Invalid request code", + .EBADSLT = "Invalid slot", + .EUNKNOWN_58 = "Unknown Error (58)", + .EBFONT = "Bad font file format", + .ENOSTR = "Device not a stream", + .ENODATA = "No data available", + .ETIME = "Timer expired", + .ENOSR = "Out of streams resources", + .ENONET = "Machine is not on the network", + .ENOPKG = "Package not installed", + .EREMOTE = "Object is remote", + .ENOLINK = "Link has been severed", + .EADV = "Advertise error", + .ESRMNT = "Srmount error", + .ECOMM = "Communication error on send", + .EPROTO = "Protocol error", + .EMULTIHOP = "Multihop attempted", + .EDOTDOT = "RFS specific error", + .EBADMSG = "Bad message", + .EOVERFLOW = "Value too large for defined data type", + .ENOTUNIQ = "Name not unique on network", + .EBADFD = "File descriptor in bad state", + .EREMCHG = "Remote address changed", + .ELIBACC = "Can not access a needed shared library", + .ELIBBAD = "Accessing a corrupted shared library", + .ELIBSCN = ".lib section in a.out corrupted", + .ELIBMAX = "Attempting to link in too many shared libraries", + .ELIBEXEC = "Cannot exec a shared library directly", + .EILSEQ = "Invalid or incomplete multibyte or wide character", + .ERESTART = "Interrupted system call should be restarted", + .ESTRPIPE = "Streams pipe error", + .EUSERS = "Too many users", + .ENOTSOCK = "Socket operation on non-socket", + .EDESTADDRREQ = "Destination address required", + .EMSGSIZE = "Message too long", + .EPROTOTYPE = "Protocol wrong type for socket", + .ENOPROTOOPT = "Protocol not available", + .EPROTONOSUPPORT = "Protocol not supported", + .ESOCKTNOSUPPORT = "Socket type not supported", + .EOPNOTSUPP = "Operation not supported", + .EPFNOSUPPORT = "Protocol family not supported", + .EAFNOSUPPORT = "Address family not supported by protocol", + .EADDRINUSE = "Address already in use", + .EADDRNOTAVAIL = "Cannot assign requested address", + .ENETDOWN = "Network is down", + .ENETUNREACH = "Network is unreachable", + .ENETRESET = "Network dropped connection on reset", + .ECONNABORTED = "Software caused connection abort", + .ECONNRESET = "Connection reset by peer", + .ENOBUFS = "No buffer space available", + .EISCONN = "Transport endpoint is already connected", + .ENOTCONN = "Transport endpoint is not connected", + .ESHUTDOWN = "Cannot send after transport endpoint shutdown", + .ETOOMANYREFS = "Too many references: cannot splice", + .ETIMEDOUT = "Connection timed out", + .ECONNREFUSED = "Connection refused", + .EHOSTDOWN = "Host is down", + .EHOSTUNREACH = "No route to host", + .EALREADY = "Operation already in progress", + .EINPROGRESS = "Operation now in progress", + .ESTALE = "Stale file handle", + .EUCLEAN = "Structure needs cleaning", + .ENOTNAM = "Not a XENIX named type file", + .ENAVAIL = "No XENIX semaphores available", + .EISNAM = "Is a named type file", + .EREMOTEIO = "Remote I/O error", + .EDQUOT = "Disk quota exceeded", + .ENOMEDIUM = "No medium found", + .EMEDIUMTYPE = "Wrong medium type", + .ECANCELED = "Operation canceled", + .ENOKEY = "Required key not available", + .EKEYEXPIRED = "Key has expired", + .EKEYREVOKED = "Key has been revoked", + .EKEYREJECTED = "Key was rejected by service", + .EOWNERDEAD = "Owner died", + .ENOTRECOVERABLE = "State not recoverable", + .ERFKILL = "Operation not possible due to RF-kill", + .EHWPOISON = "Memory page has hardware error", + } + if Platform_Error.NONE <= e && e <= max(Platform_Error) { + return pe_strings[e] + } } return "" } diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin index e4191d9aa..28c93cfae 100644 --- a/core/os/os2/errors_linux.odin +++ b/core/os/os2/errors_linux.odin @@ -4,8 +4,8 @@ package os2 import "core:sys/linux" @(rodata) -_errno_strings : [linux.Error]string = { - .NONE = "Success", +_errno_strings := [linux.Error]string{ + .NONE = "", .EPERM = "Operation not permitted", .ENOENT = "No such file or directory", .ESRCH = "No such process", diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index af5b485a6..d331bcfc8 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -35,7 +35,6 @@ ERROR_INVALID_HANDLE :: _Platform_Error(6) ERROR_NOT_ENOUGH_MEMORY :: _Platform_Error(8) ERROR_NO_MORE_FILES :: _Platform_Error(18) ERROR_HANDLE_EOF :: _Platform_Error(38) -ERROR_EOF :: General_Error.EOF ERROR_NETNAME_DELETED :: _Platform_Error(64) ERROR_FILE_EXISTS :: _Platform_Error(80) ERROR_INVALID_PARAMETER :: _Platform_Error(87) From e8d26c5797bee638e836ff75d7fad3df274467fd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 13:41:34 +0100 Subject: [PATCH 078/122] Move errors to where appropriate --- core/os/dir_windows.odin | 2 +- core/os/errors.odin | 5 +++++ core/os/file_windows.odin | 6 +++--- core/os/os_js.odin | 6 ++---- core/os/os_windows.odin | 6 ++---- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index d6028dd7e..f0a1f4ff6 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -58,7 +58,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F dir_fi, _ := file_info_from_get_file_information_by_handle("", h) if !dir_fi.is_dir { - return nil, ERROR_FILE_IS_NOT_DIR + return nil, .Not_Dir } n := n diff --git a/core/os/errors.odin b/core/os/errors.odin index c7fd12dfb..d95c7be51 100644 --- a/core/os/errors.odin +++ b/core/os/errors.odin @@ -32,6 +32,9 @@ General_Error :: enum u32 { Pattern_Has_Separator, Unsupported, + + File_Is_Pipe, + Not_Dir, } @@ -77,6 +80,8 @@ error_string :: proc "contextless" (ferr: Error) -> string { case .Invalid_Callback: return "invalid callback" case .Unsupported: return "unsupported" case .Pattern_Has_Separator: return "pattern has separator" + case .File_Is_Pipe: return "file is pipe" + case .Not_Dir: return "file is not directory" } case io.Error: switch e { diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 76f0f2c26..aafe247b3 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -195,7 +195,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { lo := i32(offset) ft := win32.GetFileType(win32.HANDLE(fd)) if ft == win32.FILE_TYPE_PIPE { - return 0, ERROR_FILE_IS_PIPE + return 0, .File_Is_Pipe } dw_ptr := win32.SetFilePointer(win32.HANDLE(fd), lo, &hi, w) @@ -278,7 +278,7 @@ will read from the location twice on *nix, and from two different locations on W */ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { if offset < 0 { - return 0, ERROR_NEGATIVE_OFFSET + return 0, .Invalid_Offset } b, offset := data, offset @@ -310,7 +310,7 @@ will write to the location twice on *nix, and to two different locations on Wind */ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { if offset < 0 { - return 0, ERROR_NEGATIVE_OFFSET + return 0, .Invalid_Offset } b, offset := data, offset diff --git a/core/os/os_js.odin b/core/os/os_js.odin index e14742900..a2ae49b6d 100644 --- a/core/os/os_js.odin +++ b/core/os/os_js.odin @@ -241,10 +241,8 @@ ERROR_PRIVILEGE_NOT_HELD :: Platform_Error.PRIVILEGE_NOT_HELD WSAEACCES :: Platform_Error.WSAEACCES WSAECONNRESET :: Platform_Error.WSAECONNRESET -// Windows reserves errors >= 1<<29 for application use -ERROR_FILE_IS_PIPE :: Platform_Error.FILE_IS_PIPE -ERROR_FILE_IS_NOT_DIR :: Platform_Error.FILE_IS_NOT_DIR -ERROR_NEGATIVE_OFFSET :: Platform_Error.NEGATIVE_OFFSET +ERROR_FILE_IS_PIPE :: General_Error.File_Is_Pipe +ERROR_FILE_IS_NOT_DIR :: General_Error.Not_Dir // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index d331bcfc8..5a080e18c 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -54,10 +54,8 @@ ERROR_PRIVILEGE_NOT_HELD :: _Platform_Error(1314) WSAEACCES :: _Platform_Error(10013) WSAECONNRESET :: _Platform_Error(10054) -// Windows reserves errors >= 1<<29 for application use -ERROR_FILE_IS_PIPE :: _Platform_Error(1<<29 + 0) -ERROR_FILE_IS_NOT_DIR :: _Platform_Error(1<<29 + 1) -ERROR_NEGATIVE_OFFSET :: _Platform_Error(1<<29 + 2) +ERROR_FILE_IS_PIPE :: General_Error.File_Is_Pipe +ERROR_FILE_IS_NOT_DIR :: General_Error.Not_Dir // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() From fff1d509d5b68e02c269b40e6739bc2234ebca8a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 14:41:55 +0100 Subject: [PATCH 079/122] Add `read_entire_file_or_err` and `write_entire_file_or_err` --- core/os/os.odin | 94 ++++++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/core/os/os.odin b/core/os/os.odin index 51bb4b88e..568c0a2aa 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -91,6 +91,7 @@ read_full :: proc(fd: Handle, buf: []byte) -> (n: int, err: Error) { } +@(require_results) file_size_from_path :: proc(path: string) -> i64 { fd, err := open(path, O_RDONLY, 0) if err != nil { @@ -105,42 +106,20 @@ file_size_from_path :: proc(path: string) -> i64 { return length } +@(require_results) read_entire_file_from_filename :: proc(name: string, allocator := context.allocator, loc := #caller_location) -> (data: []byte, success: bool) { - context.allocator = allocator - - fd, err := open(name, O_RDONLY, 0) - if err != nil { - return nil, false - } - defer close(fd) - - return read_entire_file_from_handle(fd, allocator, loc) + err: Error + data, err = read_entire_file_from_filename_or_err(name, allocator, loc) + success = err == nil + return } +@(require_results) read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator, loc := #caller_location) -> (data: []byte, success: bool) { - context.allocator = allocator - - length: i64 err: Error - if length, err = file_size(fd); err != nil { - return nil, false - } - - if length <= 0 { - return nil, true - } - - data, err = make([]byte, int(length), allocator, loc) - if data == nil || err != nil { - return nil, false - } - - bytes_read, read_err := read_full(fd, data) - if read_err != nil { - delete(data) - return nil, false - } - return data[:bytes_read], true + data, err = read_entire_file_from_handle_or_err(fd, allocator, loc) + success = err == nil + return } read_entire_file :: proc { @@ -148,7 +127,50 @@ read_entire_file :: proc { read_entire_file_from_handle, } +@(require_results) +read_entire_file_from_filename_or_err :: proc(name: string, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Error) { + context.allocator = allocator + + fd := open(name, O_RDONLY, 0) or_return + defer close(fd) + + return read_entire_file_from_handle_or_err(fd, allocator, loc) +} + +@(require_results) +read_entire_file_from_handle_or_err :: proc(fd: Handle, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Error) { + context.allocator = allocator + + length := file_size(fd) or_return + if length <= 0 { + return nil, nil + } + + data = make([]byte, int(length), allocator, loc) or_return + if data == nil { + return nil, nil + } + defer if err != nil { + delete(data, allocator) + } + + bytes_read := read_full(fd, data) or_return + data = data[:bytes_read] + return +} + +read_entire_file_or_err :: proc { + read_entire_file_from_filename_or_err, + read_entire_file_from_handle_or_err, +} + + write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (success: bool) { + return write_entire_file_or_err(name, data, truncate) == nil +} + +@(require_results) +write_entire_file_or_err :: proc(name: string, data: []byte, truncate := true) -> Error { flags: int = O_WRONLY|O_CREATE if truncate { flags |= O_TRUNC @@ -160,14 +182,11 @@ write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (succ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH } - fd, err := open(name, flags, mode) - if err != nil { - return false - } + fd := open(name, flags, mode) or_return defer close(fd) - _, write_err := write(fd, data) - return write_err == nil + _ = write(fd, data) or_return + return nil } write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Error) { @@ -185,6 +204,7 @@ heap_alloc :: runtime.heap_alloc heap_resize :: runtime.heap_resize heap_free :: runtime.heap_free +@(require_results) processor_core_count :: proc() -> int { return _processor_core_count() } From b67817517ed4929093feed67a9a0903035f329d5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 14:46:32 +0100 Subject: [PATCH 080/122] Fix replace typo --- core/os/os_haiku.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index ff06d2c80..9adca340c 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -119,7 +119,7 @@ S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK foreign libc { - @(link_name="_Errorp") __error :: proc() -> ^c.int --- + @(link_name="_errorp") __error :: proc() -> ^c.int --- @(link_name="fork") _unix_fork :: proc() -> pid_t --- @(link_name="getthrid") _unix_getthrid :: proc() -> int --- From 6a6b5061db061234120c747f23cc0e5422c2af33 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 14:47:35 +0100 Subject: [PATCH 081/122] Update core/os/os_darwin.odin Co-authored-by: Laytan --- core/os/os_darwin.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 4a317eddf..96ef178bb 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -785,7 +785,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { final_offset := i64(_unix_lseek(fd, int(offset), c.int(whence))) if final_offset == -1 { - return 0, Platform_Error.EPERM + return 0, get_last_error() } return final_offset, nil } From fc10b781af46a5ed1678d046160820de54885879 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 14:47:44 +0100 Subject: [PATCH 082/122] Update core/os/os2/process.odin Co-authored-by: Laytan --- core/os/os2/process.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os2/process.odin b/core/os/os2/process.odin index f1309e468..3f3e64668 100644 --- a/core/os/os2/process.odin +++ b/core/os/os2/process.odin @@ -370,7 +370,7 @@ Process_State :: struct { timeout (if specified) has reached zero. If the timeout is `TIMEOUT_INFINITE`, no timeout restriction is imposed and the procedure can block indefinately. - If the timeout has expired, the `GeneralPlatform_Error.Timeout` is returned as + If the timeout has expired, the `General_Error.Timeout` is returned as the error. If an error is returned for any other reason, other than timeout, the From 93fabf862891a6ac8915aed9094cecceaa3cc61b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 14:57:25 +0100 Subject: [PATCH 083/122] Replace `err != 0` with `err != nil` where possible --- core/image/general_os.odin | 2 +- core/mem/virtual/file.odin | 4 ++-- core/path/filepath/match.odin | 4 ++-- core/path/filepath/path_windows.odin | 2 +- core/path/filepath/walk.odin | 27 ++++++++++----------------- core/prof/spall/spall_linux.odin | 13 ++----------- 6 files changed, 18 insertions(+), 34 deletions(-) diff --git a/core/image/general_os.odin b/core/image/general_os.odin index 144a3470f..e1fe440a4 100644 --- a/core/image/general_os.odin +++ b/core/image/general_os.odin @@ -27,7 +27,7 @@ which :: proc{ which_file :: proc(path: string) -> Which_File_Type { f, err := os.open(path) - if err != 0 { + if err != nil { return .Unknown } header: [128]byte diff --git a/core/mem/virtual/file.odin b/core/mem/virtual/file.odin index 5d7180588..2f852b40c 100644 --- a/core/mem/virtual/file.odin +++ b/core/mem/virtual/file.odin @@ -24,7 +24,7 @@ map_file :: proc{ map_file_from_path :: proc(filename: string, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { fd, err := os.open(filename, os.O_RDWR) - if err != 0 { + if err != nil { return nil, .Open_Failure } defer os.close(fd) @@ -34,7 +34,7 @@ map_file_from_path :: proc(filename: string, flags: Map_File_Flags) -> (data: [] map_file_from_file_descriptor :: proc(fd: uintptr, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { size, os_err := os.file_size(os.Handle(fd)) - if os_err != 0 { + if os_err != nil { return nil, .Stat_Failure } if size < 0 { diff --git a/core/path/filepath/match.odin b/core/path/filepath/match.odin index 1279bdd84..7eb72b9a7 100644 --- a/core/path/filepath/match.odin +++ b/core/path/filepath/match.odin @@ -271,7 +271,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string, allocator := cont d, derr := os.open(dir, os.O_RDONLY) - if derr != 0 { + if derr != nil { return } defer os.close(d) @@ -280,7 +280,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string, allocator := cont file_info, ferr := os.fstat(d) defer os.file_info_delete(file_info) - if ferr != 0 { + if ferr != nil { return } if !file_info.is_dir { diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin index d886d71da..0dcb28cf8 100644 --- a/core/path/filepath/path_windows.odin +++ b/core/path/filepath/path_windows.odin @@ -81,7 +81,7 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Error) { abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator) full_path, err := temp_full_path(path) - if err != 0 { + if err != nil { return "", false } p := clean(full_path, allocator) diff --git a/core/path/filepath/walk.odin b/core/path/filepath/walk.odin index 9fd4c455f..51dfa71d2 100644 --- a/core/path/filepath/walk.odin +++ b/core/path/filepath/walk.odin @@ -27,12 +27,12 @@ walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Error defer os.file_info_delete(info, context.temp_allocator) skip_dir: bool - if err != 0 { + if err != nil { err, skip_dir = walk_proc(info, err, user_data) } else { err, skip_dir = _walk(info, walk_proc, user_data) } - return 0 if skip_dir else err + return nil if skip_dir else err } @@ -43,7 +43,7 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (e // ignore empty things return } - return walk_proc(info, 0, user_data) + return walk_proc(info, nil, user_data) } fis: []os.File_Info @@ -52,14 +52,14 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (e defer os.file_info_slice_delete(fis, context.temp_allocator) err1, skip_dir = walk_proc(info, err, user_data) - if err != 0 || err1 != 0 || skip_dir { + if err != nil || err1 != nil || skip_dir { err = err1 return } for fi in fis { err, skip_dir = _walk(fi, walk_proc, user_data) - if err != 0 || skip_dir { + if err != nil || skip_dir { if !fi.is_dir || !skip_dir { return } @@ -70,19 +70,12 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (e } @(private) -read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> ([]os.File_Info, os.Error) { - f, err := os.open(dir_name, os.O_RDONLY) - if err != 0 { - return nil, err - } - fis: []os.File_Info - fis, err = os.read_dir(f, -1, allocator) - os.close(f) - if err != 0 { - return nil, err - } +read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> (fis: []os.File_Info, err: os.Error) { + f := os.open(dir_name, os.O_RDONLY) or_return + defer os.close(f) + fis = os.read_dir(f, -1, allocator) or_return slice.sort_by(fis, proc(a, b: os.File_Info) -> bool { return a.name < b.name }) - return fis, 0 + return } diff --git a/core/prof/spall/spall_linux.odin b/core/prof/spall/spall_linux.odin index 89a4225d3..b25d2b336 100644 --- a/core/prof/spall/spall_linux.odin +++ b/core/prof/spall/spall_linux.odin @@ -11,20 +11,11 @@ MAX_RW :: 0x7fffffff @(no_instrumentation) _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { - if len(data) == 0 { - return 0, nil - } - for n < len(data) { chunk := data[:min(len(data), MAX_RW)] - written, errno := linux.write(linux.Fd(fd), chunk) - if errno != nil { - return n, os.Platform_Error(errno) - } - n += written + n += linux.write(linux.Fd(fd), chunk) or_return } - - return n, nil + return } CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP. From 0bedd3357ae709c1d35e86ce6e883964fea13fdd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 14:58:12 +0100 Subject: [PATCH 084/122] Disallow `err != 0` with `os.Error` when `-strict-style` is enabled --- src/check_expr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 06784a7f3..b291cbe70 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4461,7 +4461,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar case Type_Union: // IMPORTANT NOTE HACK(bill): This is just to allow for comparisons against `0` with the `os.Error` type // as a kind of transition period - if (operand->mode == Addressing_Constant && + if (!build_context.strict_style && + operand->mode == Addressing_Constant && target_type->kind == Type_Named && (c->pkg == nullptr || c->pkg->name != "os") && target_type->Named.name == "Error") { From acb1ebddf68d4611f666aa3c85ec1c28f40fafbe Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 15:01:04 +0100 Subject: [PATCH 085/122] Fix `err != 0` uses --- core/image/png/example.odin | 2 +- core/image/png/helpers.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/image/png/example.odin b/core/image/png/example.odin index cd9788bd3..ce491978b 100644 --- a/core/image/png/example.odin +++ b/core/image/png/example.odin @@ -213,7 +213,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b } fd, err := open(filename, flags, mode) - if err != 0 { + if err != nil { return false } defer close(fd) diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin index ac61378da..7b6367694 100644 --- a/core/image/png/helpers.odin +++ b/core/image/png/helpers.odin @@ -450,7 +450,7 @@ when false { } fd, fderr := open(filename, flags, mode) - if fderr != 0 { + if fderr != nil { return .Cannot_Open_File } defer close(fd) From bf948ab8aed9099cf17beb91bf75b07698661a51 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 15:07:24 +0100 Subject: [PATCH 086/122] Add stubs for `flush` on platforms that didn't have it --- core/os/os_essence.odin | 5 +++++ core/os/os_freebsd.odin | 5 +++++ core/os/os_haiku.odin | 5 +++++ core/os/os_linux.odin | 5 +++++ core/os/os_netbsd.odin | 5 +++++ core/os/os_openbsd.odin | 5 +++++ core/os/os_wasi.odin | 6 ++++++ core/os/stream.odin | 8 ++------ 8 files changed, 38 insertions(+), 6 deletions(-) diff --git a/core/os/os_essence.odin b/core/os/os_essence.odin index 71708cfbb..75c4c1156 100644 --- a/core/os/os_essence.odin +++ b/core/os/os_essence.odin @@ -53,3 +53,8 @@ write :: proc(fd: Handle, data: []u8) -> (int, Error) { seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { return (i64) (0), (Error) (1) } + +flush :: proc(fd: Handle) -> Error { + // do nothing + return nil +} \ No newline at end of file diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 3c514084e..1a38aa20c 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -442,6 +442,11 @@ close :: proc(fd: Handle) -> Error { return nil } +flush :: proc(fd: Handle) -> Error { + // do nothing + return nil +} + // If you read or write more than `INT_MAX` bytes, FreeBSD returns `EINVAL`. // In practice a read/write call would probably never read/write these big buffers all at once, // which is why the number of bytes is returned and why there are procs that will call this in a diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index 9adca340c..ffaf12aae 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -212,6 +212,11 @@ close :: proc(fd: Handle) -> Error { return nil } +flush :: proc(fd: Handle) -> Error { + // do nothing + return nil +} + // In practice a read/write call would probably never read/write these big buffers all at once, // which is why the number of bytes is returned and why there are procs that will call this in a // loop for you. diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 267ba3330..4aa4f279e 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -581,6 +581,11 @@ close :: proc(fd: Handle) -> Error { return _get_errno(unix.sys_close(int(fd))) } +flush :: proc(fd: Handle) -> Error { + // do nothing + return nil +} + // If you read or write more than `SSIZE_MAX` bytes, result is implementation defined (probably an error). // `SSIZE_MAX` is also implementation defined but usually the max of a `ssize_t` which is `max(int)` in Odin. // In practice a read/write call would probably never read/write these big buffers all at once, diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index 69d0cab8a..7905a7d4e 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -502,6 +502,11 @@ close :: proc(fd: Handle) -> Error { return nil } +flush :: proc(fd: Handle) -> Error { + // do nothing + return nil +} + // We set a max of 1GB to keep alignment and to be safe. @(private) MAX_RW :: 1 << 30 diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 30ffb3432..1c2e652b0 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -426,6 +426,11 @@ close :: proc(fd: Handle) -> Error { return nil } +flush :: proc(fd: Handle) -> Error { + // do nothing + return nil +} + // If you read or write more than `SSIZE_MAX` bytes, OpenBSD returns `EINVAL`. // In practice a read/write call would probably never read/write these big buffers all at once, // which is why the number of bytes is returned and why there are procs that will call this in a diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 9da053796..992c00f21 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -205,6 +205,12 @@ close :: proc(fd: Handle) -> Errno { err := wasi.fd_close(wasi.fd_t(fd)) return Platform_Error(err) } + +flush :: proc(fd: Handle) -> Error { + // do nothing + return nil +} + seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { n, err := wasi.fd_seek(wasi.fd_t(fd), wasi.filedelta_t(offset), wasi.whence_t(whence)) return i64(n), Platform_Error(err) diff --git a/core/os/stream.odin b/core/os/stream.odin index cb392ccaf..8acbee489 100644 --- a/core/os/stream.odin +++ b/core/os/stream.odin @@ -17,13 +17,9 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, os_err: Error switch mode { case .Close: - close(fd) + os_err = close(fd) case .Flush: - when ODIN_OS == .Windows || ODIN_OS == .Darwin || ODIN_OS == .JS { - flush(fd) - } else { - // TOOD(bill): other operating systems - } + os_err = flush(fd) case .Read: n_int, os_err = read(fd, p) n = i64(n_int) From c078b2dd1be617e6687a3a5ffc919a45bbabb5bf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 15:24:26 +0100 Subject: [PATCH 087/122] Add `@(require_results)` --- core/os/dir_windows.odin | 1 + core/os/errors.odin | 6 ++++ core/os/file_windows.odin | 14 ++++++-- core/os/os_darwin.odin | 65 ++++++++++++++++++++++++------------ core/os/os_freebsd.odin | 51 +++++++++++++++++++--------- core/os/os_haiku.odin | 27 ++++++++++----- core/os/os_js.odin | 21 ++++++++++-- core/os/os_linux.odin | 70 ++++++++++++++++++++++++++------------- core/os/os_netbsd.odin | 52 ++++++++++++++++++++--------- core/os/os_openbsd.odin | 50 +++++++++++++++++++--------- core/os/os_wasi.odin | 9 +++-- core/os/os_windows.odin | 28 +++++++++++----- core/os/stat_unix.odin | 9 +++-- core/os/stat_windows.odin | 27 ++++++++------- 14 files changed, 297 insertions(+), 133 deletions(-) diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index f0a1f4ff6..ae3e6922c 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -6,6 +6,7 @@ import "base:runtime" @(require_results) read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Error) { + @(require_results) find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) { // Ignore "." and ".." if d.cFileName[0] == '.' && d.cFileName[1] == 0 { diff --git a/core/os/errors.odin b/core/os/errors.odin index d95c7be51..691397f4b 100644 --- a/core/os/errors.odin +++ b/core/os/errors.odin @@ -139,6 +139,12 @@ _error_string :: proc "contextless" (e: Platform_Error) -> string where intrinsi return "" } + when ODIN_OS == .Darwin { + if s := string(_darwin_string_error(i32(e))); s != "" { + return s + } + } + when ODIN_OS != .Linux { @(require_results) binary_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) #no_bounds_check { diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index aafe247b3..3f6f781aa 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -5,10 +5,12 @@ import "base:intrinsics" import "base:runtime" import "core:unicode/utf16" +@(require_results) is_path_separator :: proc(c: byte) -> bool { return c == '/' || c == '\\' } +@(require_results) open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Error) { if len(path) == 0 { return INVALID_HANDLE, General_Error.Not_Exist @@ -96,7 +98,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { return int(total_write), nil } -@(private="file") +@(private="file", require_results) read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Error) { if len(b) == 0 { return 0, nil @@ -206,6 +208,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { return i64(hi)<<32 + i64(dw_ptr), nil } +@(require_results) file_size :: proc(fd: Handle) -> (i64, Error) { length: win32.LARGE_INTEGER err: Error @@ -331,6 +334,7 @@ stdout := get_std_handle(uint(win32.STD_OUTPUT_HANDLE)) stderr := get_std_handle(uint(win32.STD_ERROR_HANDLE)) +@(require_results) get_std_handle :: proc "contextless" (h: uint) -> Handle { fd := win32.GetStdHandle(win32.DWORD(h)) return Handle(fd) @@ -345,6 +349,7 @@ exists :: proc(path: string) -> bool { return attribs != win32.INVALID_FILE_ATTRIBUTES } +@(require_results) is_file :: proc(path: string) -> bool { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wpath := win32.utf8_to_wstring(path, context.temp_allocator) @@ -356,6 +361,7 @@ is_file :: proc(path: string) -> bool { return false } +@(require_results) is_dir :: proc(path: string) -> bool { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wpath := win32.utf8_to_wstring(path, context.temp_allocator) @@ -370,6 +376,7 @@ is_dir :: proc(path: string) -> bool { // NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName @private cwd_lock := win32.SRWLOCK{} // zero is initialized +@(require_results) get_current_directory :: proc(allocator := context.allocator) -> string { win32.AcquireSRWLockExclusive(&cwd_lock) @@ -426,7 +433,7 @@ remove_directory :: proc(path: string) -> (err: Error) { -@(private) +@(private, require_results) is_abs :: proc(path: string) -> bool { if len(path) > 0 && path[0] == '/' { return true @@ -442,7 +449,7 @@ is_abs :: proc(path: string) -> bool { return false } -@(private) +@(private, require_results) fix_long_path :: proc(path: string) -> string { if len(path) < 248 { return path @@ -574,6 +581,7 @@ remove :: proc(name: string) -> Error { } +@(require_results) pipe :: proc() -> (r, w: Handle, err: Error) { sa: win32.SECURITY_ATTRIBUTES sa.nLength = size_of(win32.SECURITY_ATTRIBUTES) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 96ef178bb..09cdd84d0 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -562,13 +562,13 @@ S_ISUID :: 0o4000 // Set user id on execution S_ISGID :: 0o2000 // Set group id on execution S_ISVTX :: 0o1000 // Directory restrcted delete -S_ISLNK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFLNK } -S_ISREG :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFREG } -S_ISDIR :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFDIR } -S_ISCHR :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFCHR } -S_ISBLK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFBLK } -S_ISFIFO :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFIFO } -S_ISSOCK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFSOCK } +@(require_results) S_ISLNK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFLNK } +@(require_results) S_ISREG :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFREG } +@(require_results) S_ISDIR :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFDIR } +@(require_results) S_ISCHR :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFCHR } +@(require_results) S_ISBLK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFBLK } +@(require_results) S_ISFIFO :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFIFO } +@(require_results) S_ISSOCK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFSOCK } R_OK :: 4 // Test for read permission W_OK :: 2 // Test for write permission @@ -667,11 +667,13 @@ get_last_error :: proc "contextless" () -> Error { return Platform_Error(__error()^) } +@(require_results) get_last_error_string :: proc() -> string { return string(_darwin_string_error(__error()^)) } +@(require_results) open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (handle: Handle, err: Error) { isDir := is_dir_path(path) flags := flags @@ -790,6 +792,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { return final_offset, nil } +@(require_results) file_size :: proc(fd: Handle) -> (i64, Error) { prev, _ := seek(fd, 0, SEEK_CUR) size, err := seek(fd, 0, SEEK_END) @@ -804,12 +807,14 @@ stdin: Handle = 0 // get_std_handle(win32.STD_INPUT_HANDLE); stdout: Handle = 1 // get_std_handle(win32.STD_OUTPUT_HANDLE); stderr: Handle = 2 // get_std_handle(win32.STD_ERROR_HANDLE); +@(require_results) last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Error) { s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } +@(require_results) last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds @@ -817,10 +822,12 @@ last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { } +@(require_results) is_path_separator :: proc(r: rune) -> bool { return r == '/' } +@(require_results) is_file_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) if err != nil { @@ -829,6 +836,7 @@ is_file_handle :: proc(fd: Handle) -> bool { return S_ISREG(s.mode) } +@(require_results) is_file_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat err: Error @@ -844,6 +852,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { } +@(require_results) is_dir_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) if err != nil { @@ -852,6 +861,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { return S_ISDIR(s.mode) } +@(require_results) is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat err: Error @@ -869,6 +879,7 @@ is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { is_file :: proc {is_file_path, is_file_handle} is_dir :: proc {is_dir_path, is_dir_handle} +@(require_results) exists :: proc(path: string) -> bool { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath := strings.clone_to_cstring(path, context.temp_allocator) @@ -893,7 +904,7 @@ remove :: proc(path: string) -> Error { return nil } -@private +@(private, require_results) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -906,7 +917,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -919,7 +930,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat result := _unix_fstat(fd, &s) @@ -929,7 +940,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { @@ -938,7 +949,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { return dirp, nil } -@private +@(private) _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { @@ -947,12 +958,12 @@ _closedir :: proc(dirp: Dir) -> Error { return nil } -@private +@(private) _rewinddir :: proc(dirp: Dir) { _unix_rewinddir(dirp) } -@private +@(private, require_results) _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) @@ -971,7 +982,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) return } -@private +@(private, require_results) _readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -994,12 +1005,14 @@ _readlink :: proc(path: string) -> (string, Error) { } } +@(require_results) absolute_path_from_handle :: proc(fd: Handle) -> (path: string, err: Error) { buf: [DARWIN_MAXPATHLEN]byte _ = fcntl(int(fd), F_GETPATH, int(uintptr(&buf[0]))) or_return return strings.clone_from_cstring(cstring(&buf[0])) } +@(require_results) absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { @@ -1031,6 +1044,7 @@ flush :: proc(fd: Handle) -> Error { return cast(Platform_Error)_unix_fsync(fd) } +@(require_results) lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) @@ -1041,6 +1055,7 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin return strings.clone(string(cstr), allocator), true } +@(require_results) get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return @@ -1067,6 +1082,7 @@ unset_env :: proc(key: string) -> Error { return nil } +@(require_results) get_current_directory :: proc() -> string { page_size := get_page_size() // NOTE(tetra): See note in os_linux.odin/get_current_directory. buf := make([dynamic]u8, page_size) @@ -1109,6 +1125,7 @@ exit :: proc "contextless" (code: int) -> ! { _unix_exit(i32(code)) } +@(require_results) current_thread_id :: proc "contextless" () -> int { tid: u64 // NOTE(Oskar): available from OSX 10.6 and iOS 3.2. @@ -1119,12 +1136,14 @@ current_thread_id :: proc "contextless" () -> int { return int(tid) } +@(require_results) dlopen :: proc(filename: string, flags: int) -> rawptr { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(filename, context.temp_allocator) handle := _unix_dlopen(cstr, flags) return handle } +@(require_results) dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil) runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() @@ -1140,6 +1159,7 @@ dlerror :: proc() -> string { return string(_unix_dlerror()) } +@(require_results) get_page_size :: proc() -> int { // NOTE(tetra): The page size never changes, so why do anything complicated // if we don't have to. @@ -1152,7 +1172,7 @@ get_page_size :: proc() -> int { return page_size } -@(private) +@(private, require_results) _processor_core_count :: proc() -> int { count : int = 0 count_size := size_of(count) @@ -1165,6 +1185,7 @@ _processor_core_count :: proc() -> int { return 1 } +@(require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for _, i in res { @@ -1173,6 +1194,7 @@ _alloc_command_line_arguments :: proc() -> []string { return res } +@(require_results) socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { result := _unix_socket(domain, type, protocol) if result < 0 { @@ -1181,7 +1203,8 @@ socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { return Socket(result), nil } -connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { +@(require_results) +connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> Error { result := _unix_connect(int(sd), addr, len) if result < 0 { return get_last_error() @@ -1189,7 +1212,7 @@ connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { return nil } -bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { +bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> Error { result := _unix_bind(int(sd), addr, len) if result < 0 { return get_last_error() @@ -1205,7 +1228,7 @@ accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Error) { return Socket(result), nil } -listen :: proc(sd: Socket, backlog: int) -> (Error) { +listen :: proc(sd: Socket, backlog: int) -> Error { result := _unix_listen(int(sd), backlog) if result < 0 { return get_last_error() @@ -1213,7 +1236,7 @@ listen :: proc(sd: Socket, backlog: int) -> (Error) { return nil } -setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> (Error) { +setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Error { result := _unix_setsockopt(int(sd), level, optname, optval, optlen) if result < 0 { return get_last_error() @@ -1261,7 +1284,7 @@ send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { return u32(result), nil } -shutdown :: proc(sd: Socket, how: int) -> (Error) { +shutdown :: proc(sd: Socket, how: int) -> Error { result := _unix_shutdown(int(sd), how) if result < 0 { return get_last_error() diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 1a38aa20c..c7955368e 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -353,13 +353,13 @@ S_ISGID :: 0o2000 // Set group id on execution S_ISVTX :: 0o1000 // Directory restrcted delete -S_ISLNK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFLNK } -S_ISREG :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFREG } -S_ISDIR :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFDIR } -S_ISCHR :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFCHR } -S_ISBLK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFBLK } -S_ISFIFO :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFIFO } -S_ISSOCK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFSOCK } +@(require_results) S_ISLNK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFLNK } +@(require_results) S_ISREG :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFREG } +@(require_results) S_ISDIR :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFDIR } +@(require_results) S_ISCHR :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFCHR } +@(require_results) S_ISBLK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFBLK } +@(require_results) S_ISFIFO :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFIFO } +@(require_results) S_ISSOCK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFSOCK } F_OK :: 0 // Test for file existance X_OK :: 1 // Test for execute permission @@ -415,6 +415,7 @@ foreign dl { @(link_name="pthread_getthreadid_np") pthread_getthreadid_np :: proc() -> c.int --- } +@(require_results) is_path_separator :: proc(r: rune) -> bool { return r == '/' } @@ -424,6 +425,7 @@ get_last_error :: proc "contextless" () -> Error { return Platform_Error(__Error_location()^) } +@(require_results) open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -505,6 +507,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { return res, nil } +@(require_results) file_size :: proc(fd: Handle) -> (size: i64, err: Error) { size = -1 s := _fstat(fd) or_return @@ -553,6 +556,7 @@ remove_directory :: proc(path: string) -> Error { return nil } +@(require_results) is_file_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) if err != nil { @@ -561,6 +565,7 @@ is_file_handle :: proc(fd: Handle) -> bool { return S_ISREG(s.mode) } +@(require_results) is_file_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat err: Error @@ -575,6 +580,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { return S_ISREG(s.mode) } +@(require_results) is_dir_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) if err != nil { @@ -583,6 +589,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { return S_ISDIR(s.mode) } +@(require_results) is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat err: Error @@ -610,6 +617,7 @@ stderr: Handle = 2 last_write_time :: proc(fd: Handle) -> File_Time {} last_write_time_by_name :: proc(name: string) -> File_Time {} */ +@(require_results) last_write_time :: proc(fd: Handle) -> (File_Time, Error) { s, err := _fstat(fd) if err != nil { @@ -619,6 +627,7 @@ last_write_time :: proc(fd: Handle) -> (File_Time, Error) { return File_Time(modified), nil } +@(require_results) last_write_time_by_name :: proc(name: string) -> (File_Time, Error) { s, err := _stat(name) if err != nil { @@ -628,7 +637,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Error) { return File_Time(modified), nil } -@private +@(private, require_results) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -640,7 +649,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -654,7 +663,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat = --- result := _unix_fstat(fd, &s) @@ -664,7 +673,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { @@ -673,7 +682,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { return dirp, nil } -@private +@(private) _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { @@ -682,12 +691,12 @@ _closedir :: proc(dirp: Dir) -> Error { return nil } -@private +@(private) _rewinddir :: proc(dirp: Dir) { _unix_rewinddir(dirp) } -@private +@(private, require_results) _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) @@ -705,7 +714,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) return } -@private +@(private, require_results) _readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) @@ -730,6 +739,7 @@ _readlink :: proc(path: string) -> (string, Error) { return "", Error{} } +@(require_results) absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { // NOTE(Feoramund): The situation isn't ideal, but this was the best way I // could find to implement this. There are a couple outstanding bug reports @@ -752,6 +762,7 @@ absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { return path, nil } +@(require_results) absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { @@ -784,6 +795,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) { return true, nil } +@(require_results) lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) @@ -795,11 +807,13 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin return strings.clone(string(cstr), allocator), true } +@(require_results) get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } +@(require_results) get_current_directory :: proc() -> string { // NOTE(tetra): I would use PATH_MAX here, but I was not able to find // an authoritative value for it across all systems. @@ -835,16 +849,19 @@ exit :: proc "contextless" (code: int) -> ! { _unix_exit(c.int(code)) } +@(require_results) current_thread_id :: proc "contextless" () -> int { return cast(int) pthread_getthreadid_np() } +@(require_results) dlopen :: proc(filename: string, flags: int) -> rawptr { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(filename, context.temp_allocator) handle := _unix_dlopen(cstr, c.int(flags)) return handle } +@(require_results) dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil) runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() @@ -860,6 +877,7 @@ dlerror :: proc() -> string { return string(_unix_dlerror()) } +@(require_results) get_page_size :: proc() -> int { // NOTE(tetra): The page size never changes, so why do anything complicated // if we don't have to. @@ -872,7 +890,7 @@ get_page_size :: proc() -> int { return page_size } -@(private) +@(private, require_results) _processor_core_count :: proc() -> int { count : int = 0 count_size := size_of(count) @@ -886,6 +904,7 @@ _processor_core_count :: proc() -> int { } +@(require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index ffaf12aae..7f1ec7089 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -177,6 +177,7 @@ Dirent :: struct { Dir :: distinct rawptr // DIR* +@(require_results) is_path_separator :: proc(r: rune) -> bool { return r == '/' } @@ -186,6 +187,7 @@ get_last_error :: proc "contextless" () -> Error { return Platform_Error(__error()^) } +@(require_results) fork :: proc() -> (Pid, Error) { pid := _unix_fork() if pid == -1 { @@ -194,6 +196,7 @@ fork :: proc() -> (Pid, Error) { return Pid(pid), nil } +@(require_results) open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -274,6 +277,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { return res, nil } +@(require_results) file_size :: proc(fd: Handle) -> (i64, Error) { s, err := _fstat(fd) if err != nil { @@ -285,6 +289,7 @@ file_size :: proc(fd: Handle) -> (i64, Error) { // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() +@(require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { @@ -293,7 +298,7 @@ _alloc_command_line_arguments :: proc() -> []string { return res } -@private +@(private, require_results) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -307,7 +312,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -321,7 +326,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { // deliberately uninitialized s: OS_Stat = --- @@ -332,7 +337,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { return s, nil } -@private +@(private) _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { @@ -341,7 +346,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { return dirp, nil } -@private +@(private) _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { @@ -350,12 +355,12 @@ _closedir :: proc(dirp: Dir) -> Error { return nil } -@private +@(private) _rewinddir :: proc(dirp: Dir) { _unix_rewinddir(dirp) } -@private +@(private, require_results) _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) @@ -373,7 +378,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) return } -@private +@(private, require_results) _readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -395,10 +400,12 @@ _readlink :: proc(path: string) -> (string, Error) { } } +@(require_results) absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { return "", Error(ENOSYS) } +@(require_results) absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { @@ -430,6 +437,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) { return true, nil } +@(require_results) lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) @@ -440,12 +448,13 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin return strings.clone(string(cstr), allocator), true } +@(require_results) get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } -@(private) +@(private, require_results) _processor_core_count :: proc() -> int { info: haiku.system_info haiku.get_system_info(&info) diff --git a/core/os/os_js.odin b/core/os/os_js.odin index a2ae49b6d..eb434c727 100644 --- a/core/os/os_js.odin +++ b/core/os/os_js.odin @@ -3,10 +3,12 @@ package os import "base:runtime" +@(require_results) is_path_separator :: proc(c: byte) -> bool { return c == '/' || c == '\\' } +@(require_results) open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Error) { unimplemented("core:os procedure not supported on JS target") } @@ -38,6 +40,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { unimplemented("core:os procedure not supported on JS target") } +@(require_results) file_size :: proc(fd: Handle) -> (i64, Error) { unimplemented("core:os procedure not supported on JS target") } @@ -65,20 +68,24 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) stdout: Handle = 1 stderr: Handle = 2 +@(require_results) get_std_handle :: proc "contextless" (h: uint) -> Handle { context = runtime.default_context() unimplemented("core:os procedure not supported on JS target") } +@(require_results) exists :: proc(path: string) -> bool { unimplemented("core:os procedure not supported on JS target") } +@(require_results) is_file :: proc(path: string) -> bool { unimplemented("core:os procedure not supported on JS target") } +@(require_results) is_dir :: proc(path: string) -> bool { unimplemented("core:os procedure not supported on JS target") } @@ -86,6 +93,7 @@ is_dir :: proc(path: string) -> bool { // NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName //@private cwd_lock := win32.SRWLOCK{} // zero is initialized +@(require_results) get_current_directory :: proc(allocator := context.allocator) -> string { unimplemented("core:os procedure not supported on JS target") } @@ -111,12 +119,12 @@ remove_directory :: proc(path: string) -> (err: Error) { -@(private) +@(private, require_results) is_abs :: proc(path: string) -> bool { unimplemented("core:os procedure not supported on JS target") } -@(private) +@(private, require_results) fix_long_path :: proc(path: string) -> string { unimplemented("core:os procedure not supported on JS target") } @@ -151,10 +159,12 @@ remove :: proc(name: string) -> Error { } +@(require_results) pipe :: proc() -> (r, w: Handle, err: Error) { unimplemented("core:os procedure not supported on JS target") } +@(require_results) read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Error) { unimplemented("core:os procedure not supported on JS target") } @@ -251,20 +261,23 @@ args := _alloc_command_line_arguments() +@(require_results) last_write_time :: proc(fd: Handle) -> (File_Time, Error) { unimplemented("core:os procedure not supported on JS target") } +@(require_results) last_write_time_by_name :: proc(name: string) -> (File_Time, Error) { unimplemented("core:os procedure not supported on JS target") } +@(require_results) get_page_size :: proc() -> int { unimplemented("core:os procedure not supported on JS target") } -@(private) +@(private, require_results) _processor_core_count :: proc() -> int { unimplemented("core:os procedure not supported on JS target") } @@ -276,6 +289,7 @@ exit :: proc "contextless" (code: int) -> ! { +@(require_results) current_thread_id :: proc "contextless" () -> int { context = runtime.default_context() unimplemented("core:os procedure not supported on JS target") @@ -283,6 +297,7 @@ current_thread_id :: proc "contextless" () -> int { +@(require_results) _alloc_command_line_arguments :: proc() -> []string { return nil } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 4aa4f279e..1e110d18f 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -448,13 +448,13 @@ S_ISGID :: 0o2000 // Set group id on execution S_ISVTX :: 0o1000 // Directory restrcted delete -S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK } -S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG } -S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR } -S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR } -S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK } -S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO } -S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK } +@(require_results) S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK } +@(require_results) S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG } +@(require_results) S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR } +@(require_results) S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR } +@(require_results) S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK } +@(require_results) S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO } +@(require_results) S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK } F_OK :: 0 // Test for file existance X_OK :: 1 // Test for execute permission @@ -506,12 +506,13 @@ foreign dl { @(link_name="freeifaddrs") _freeifaddrs :: proc(ifa: ^ifaddrs) --- } +@(require_results) is_path_separator :: proc(r: rune) -> bool { return r == '/' } // determine errno from syscall return value -@private +@(private, require_results) _get_errno :: proc(res: int) -> Error { if res < 0 && res > -4096 { return Platform_Error(-res) @@ -536,7 +537,7 @@ get_last_error :: proc "contextless" () -> Error { return err } -personality :: proc(persona: u64) -> (Error) { +personality :: proc(persona: u64) -> Error { res := unix.sys_personality(persona) if res == -1 { return _get_errno(res) @@ -544,6 +545,7 @@ personality :: proc(persona: u64) -> (Error) { return nil } +@(require_results) fork :: proc() -> (Pid, Error) { pid := unix.sys_fork() if pid == -1 { @@ -567,6 +569,7 @@ execvp :: proc(path: string, args: []string) -> Error { } +@(require_results) open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0o000) -> (Handle, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -659,6 +662,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { return i64(res), nil } +@(require_results) file_size :: proc(fd: Handle) -> (i64, Error) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- @@ -694,6 +698,7 @@ remove_directory :: proc(path: string) -> Error { return _get_errno(unix.sys_rmdir(path_cstr)) } +@(require_results) is_file_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) if err != nil { @@ -702,6 +707,7 @@ is_file_handle :: proc(fd: Handle) -> bool { return S_ISREG(s.mode) } +@(require_results) is_file_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat err: Error @@ -717,6 +723,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { } +@(require_results) is_dir_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) if err != nil { @@ -725,6 +732,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { return S_ISDIR(s.mode) } +@(require_results) is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat err: Error @@ -742,6 +750,7 @@ is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { is_file :: proc {is_file_path, is_file_handle} is_dir :: proc {is_dir_path, is_dir_handle} +@(require_results) exists :: proc(path: string) -> bool { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath := strings.clone_to_cstring(path, context.temp_allocator) @@ -759,19 +768,21 @@ stderr: Handle = 2 last_write_time :: proc(fd: Handle) -> File_Time {} last_write_time_by_name :: proc(name: string) -> File_Time {} */ +@(require_results) last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Error) { s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } +@(require_results) last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } -@private +@(private, require_results) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -785,7 +796,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -799,7 +810,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- @@ -810,7 +821,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { @@ -819,7 +830,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { return dirp, nil } -@private +@(private) _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { @@ -828,12 +839,12 @@ _closedir :: proc(dirp: Dir) -> Error { return nil } -@private +@(private) _rewinddir :: proc(dirp: Dir) { _unix_rewinddir(dirp) } -@private +@(private, require_results) _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) @@ -853,7 +864,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) return } -@private +@(private, require_results) _readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -876,6 +887,7 @@ _readlink :: proc(path: string) -> (string, Error) { } } +@(require_results) absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { buf : [256]byte fd_str := strconv.itoa( buf[:], cast(int)fd ) @@ -886,6 +898,7 @@ absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { return _readlink(procfs_path) } +@(require_results) absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { @@ -916,6 +929,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) { return true, nil } +@(require_results) lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) @@ -927,6 +941,7 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin return strings.clone(string(cstr), allocator), true } +@(require_results) get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return @@ -954,6 +969,7 @@ unset_env :: proc(key: string) -> Error { return nil } +@(require_results) get_current_directory :: proc() -> string { // NOTE(tetra): I would use PATH_MAX here, but I was not able to find // an authoritative value for it across all systems. @@ -990,16 +1006,19 @@ exit :: proc "contextless" (code: int) -> ! { _unix_exit(c.int(code)) } +@(require_results) current_thread_id :: proc "contextless" () -> int { return unix.sys_gettid() } +@(require_results) dlopen :: proc(filename: string, flags: int) -> rawptr { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(filename, context.temp_allocator) handle := _unix_dlopen(cstr, c.int(flags)) return handle } +@(require_results) dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil) runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() @@ -1015,6 +1034,7 @@ dlerror :: proc() -> string { return string(_unix_dlerror()) } +@(require_results) get_page_size :: proc() -> int { // NOTE(tetra): The page size never changes, so why do anything complicated // if we don't have to. @@ -1027,11 +1047,12 @@ get_page_size :: proc() -> int { return page_size } -@(private) +@(private, require_results) _processor_core_count :: proc() -> int { return int(_unix_get_nprocs()) } +@(require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { @@ -1040,6 +1061,7 @@ _alloc_command_line_arguments :: proc() -> []string { return res } +@(require_results) socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { result := unix.sys_socket(domain, type, protocol) if result < 0 { @@ -1048,7 +1070,7 @@ socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { return Socket(result), nil } -bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { +bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> Error { result := unix.sys_bind(int(sd), addr, len) if result < 0 { return _get_errno(result) @@ -1057,7 +1079,7 @@ bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { } -connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { +connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> Error { result := unix.sys_connect(int(sd), addr, len) if result < 0 { return _get_errno(result) @@ -1073,7 +1095,7 @@ accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Error) { return Socket(result), nil } -listen :: proc(sd: Socket, backlog: int) -> (Error) { +listen :: proc(sd: Socket, backlog: int) -> Error { result := unix.sys_listen(int(sd), backlog) if result < 0 { return _get_errno(result) @@ -1081,7 +1103,7 @@ listen :: proc(sd: Socket, backlog: int) -> (Error) { return nil } -setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> (Error) { +setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Error { result := unix.sys_setsockopt(int(sd), level, optname, optval, optlen) if result < 0 { return _get_errno(result) @@ -1123,7 +1145,7 @@ send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { return u32(result), nil } -shutdown :: proc(sd: Socket, how: int) -> (Error) { +shutdown :: proc(sd: Socket, how: int) -> Error { result := unix.sys_shutdown(int(sd), how) if result < 0 { return _get_errno(result) @@ -1139,6 +1161,7 @@ fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Error) { return result, nil } +@(require_results) poll :: proc(fds: []pollfd, timeout: int) -> (int, Error) { result := unix.sys_poll(raw_data(fds), uint(len(fds)), timeout) if result < 0 { @@ -1147,6 +1170,7 @@ poll :: proc(fds: []pollfd, timeout: int) -> (int, Error) { return result, nil } +@(require_results) ppoll :: proc(fds: []pollfd, timeout: ^unix.timespec, sigmask: ^sigset_t) -> (int, Error) { result := unix.sys_ppoll(raw_data(fds), uint(len(fds)), timeout, sigmask, size_of(sigset_t)) if result < 0 { diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index 7905a7d4e..c41dc6aa6 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -407,13 +407,13 @@ S_ISUID :: 0o4000 // Set user id on execution S_ISGID :: 0o2000 // Set group id on execution S_ISVTX :: 0o1000 // Directory restrcted delete -S_ISLNK :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFLNK } -S_ISREG :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFREG } -S_ISDIR :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFDIR } -S_ISCHR :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFCHR } -S_ISBLK :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFBLK } -S_ISFIFO :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFIFO } -S_ISSOCK :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFSOCK } +@(require_results) S_ISLNK :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFLNK } +@(require_results) S_ISREG :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFREG } +@(require_results) S_ISDIR :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFDIR } +@(require_results) S_ISCHR :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFCHR } +@(require_results) S_ISBLK :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFBLK } +@(require_results) S_ISFIFO :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFIFO } +@(require_results) S_ISSOCK :: #force_inline proc "contextless" (m: mode_t) -> bool { return (m & S_IFMT) == S_IFSOCK } F_OK :: 0 // Test for file existance X_OK :: 1 // Test for execute permission @@ -561,6 +561,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { return res, nil } +@(require_results) file_size :: proc(fd: Handle) -> (size: i64, err: Error) { size = -1 s := _fstat(fd) or_return @@ -609,6 +610,7 @@ remove_directory :: proc(path: string) -> Error { return nil } +@(require_results) is_file_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) if err != nil { @@ -617,6 +619,7 @@ is_file_handle :: proc(fd: Handle) -> bool { return S_ISREG(s.mode) } +@(require_results) is_file_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat err: Error @@ -631,6 +634,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { return S_ISREG(s.mode) } +@(require_results) is_dir_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) if err != nil { @@ -639,6 +643,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { return S_ISDIR(s.mode) } +@(require_results) is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat err: Error @@ -656,6 +661,7 @@ is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { is_file :: proc {is_file_path, is_file_handle} is_dir :: proc {is_dir_path, is_dir_handle} +@(require_results) exists :: proc(path: string) -> bool { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath := strings.clone_to_cstring(path, context.temp_allocator) @@ -663,6 +669,7 @@ exists :: proc(path: string) -> bool { return res == 0 } +@(require_results) fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Error) { result := _unix_fcntl(Handle(fd), c.int(cmd), uintptr(arg)) if result < 0 { @@ -677,19 +684,21 @@ stdin: Handle = 0 stdout: Handle = 1 stderr: Handle = 2 +@(require_results) last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Error) { s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } +@(require_results) last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } -@private +@(private, require_results) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -701,7 +710,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -715,7 +724,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat = --- result := _unix_fstat(fd, &s) @@ -725,7 +734,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { @@ -734,7 +743,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { return dirp, nil } -@private +@(private) _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { @@ -743,12 +752,12 @@ _closedir :: proc(dirp: Dir) -> Error { return nil } -@private +@(private) _rewinddir :: proc(dirp: Dir) { _unix_rewinddir(dirp) } -@private +@(private, require_results) _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) @@ -767,7 +776,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) return } -@private +@(private, require_results) _readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) @@ -792,12 +801,14 @@ _readlink :: proc(path: string) -> (string, Error) { return "", Error{} } +@(require_results) absolute_path_from_handle :: proc(fd: Handle) -> (path: string, err: Error) { buf: [MAX_PATH]byte _ = fcntl(int(fd), F_GETPATH, int(uintptr(&buf[0]))) or_return return strings.clone_from_cstring(cstring(&buf[0])) } +@(require_results) absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { @@ -829,6 +840,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) { return true, nil } +@(require_results) lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) @@ -840,11 +852,13 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin return strings.clone(string(cstr), allocator), true } +@(require_results) get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } +@(require_results) get_current_directory :: proc() -> string { // NOTE(tetra): I would use PATH_MAX here, but I was not able to find // an authoritative value for it across all systems. @@ -880,10 +894,12 @@ exit :: proc "contextless" (code: int) -> ! { _unix_exit(c.int(code)) } +@(require_results) current_thread_id :: proc "contextless" () -> int { return int(_lwp_self()) } +@(require_results) dlopen :: proc(filename: string, flags: int) -> rawptr { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(filename, context.temp_allocator) @@ -891,6 +907,7 @@ dlopen :: proc(filename: string, flags: int) -> rawptr { return handle } +@(require_results) dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil) runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() @@ -904,10 +921,12 @@ dlclose :: proc(handle: rawptr) -> bool { return _unix_dlclose(handle) == 0 } +@(require_results) dlerror :: proc() -> string { return string(_unix_dlerror()) } +@(require_results) get_page_size :: proc() -> int { // NOTE(tetra): The page size never changes, so why do anything complicated // if we don't have to. @@ -920,7 +939,7 @@ get_page_size :: proc() -> int { return page_size } -@(private) +@(private, require_results) _processor_core_count :: proc() -> int { count : int = 0 count_size := size_of(count) @@ -933,6 +952,7 @@ _processor_core_count :: proc() -> int { return 1 } +@(require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 1c2e652b0..1cd26211e 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -322,13 +322,13 @@ S_ISUID :: 0o4000 // Set user id on execution S_ISGID :: 0o2000 // Set group id on execution S_ISTXT :: 0o1000 // Sticky bit -S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK } -S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG } -S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR } -S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR } -S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK } -S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO } -S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK } +@(require_results) S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK } +@(require_results) S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG } +@(require_results) S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR } +@(require_results) S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR } +@(require_results) S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK } +@(require_results) S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO } +@(require_results) S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK } F_OK :: 0x00 // Test for file existance X_OK :: 0x01 // Test for execute permission @@ -489,6 +489,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { return res, nil } +@(require_results) file_size :: proc(fd: Handle) -> (size: i64, err: Error) { size = -1 s := _fstat(fd) or_return @@ -537,6 +538,7 @@ remove_directory :: proc(path: string) -> Error { return nil } +@(require_results) is_file_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) if err != nil { @@ -545,6 +547,7 @@ is_file_handle :: proc(fd: Handle) -> bool { return S_ISREG(s.mode) } +@(require_results) is_file_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat err: Error @@ -559,6 +562,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { return S_ISREG(s.mode) } +@(require_results) is_dir_handle :: proc(fd: Handle) -> bool { s, err := _fstat(fd) if err != nil { @@ -567,6 +571,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { return S_ISDIR(s.mode) } +@(require_results) is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { s: OS_Stat err: Error @@ -594,19 +599,21 @@ stderr: Handle = 2 last_write_time :: proc(fd: Handle) -> File_Time {} last_write_time_by_name :: proc(name: string) -> File_Time {} */ +@(require_results) last_write_time :: proc(fd: Handle) -> (time: File_Time, err: Error) { s := _fstat(fd) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } +@(require_results) last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { s := _stat(name) or_return modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds return File_Time(modified), nil } -@private +@(private, require_results) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -620,7 +627,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -634,7 +641,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { // deliberately uninitialized s: OS_Stat = --- @@ -645,7 +652,7 @@ _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { return s, nil } -@private +@(private, require_results) _fdopendir :: proc(fd: Handle) -> (Dir, Error) { dirp := _unix_fdopendir(fd) if dirp == cast(Dir)nil { @@ -654,7 +661,7 @@ _fdopendir :: proc(fd: Handle) -> (Dir, Error) { return dirp, nil } -@private +@(private) _closedir :: proc(dirp: Dir) -> Error { rc := _unix_closedir(dirp) if rc != 0 { @@ -663,12 +670,12 @@ _closedir :: proc(dirp: Dir) -> Error { return nil } -@private +@(private) _rewinddir :: proc(dirp: Dir) { _unix_rewinddir(dirp) } -@private +@(private, require_results) _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) { result: ^Dirent rc := _unix_readdir_r(dirp, &entry, &result) @@ -687,7 +694,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Error, end_of_stream: bool) return } -@private +@(private, require_results) _readlink :: proc(path: string) -> (string, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -710,10 +717,12 @@ _readlink :: proc(path: string) -> (string, Error) { } // XXX OpenBSD +@(require_results) absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { return "", Error(ENOSYS) } +@(require_results) absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { rel := rel if rel == "" { @@ -744,6 +753,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) { return true, nil } +@(require_results) lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) @@ -754,11 +764,13 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin return strings.clone(string(cstr), allocator), true } +@(require_results) get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } +@(require_results) get_current_directory :: proc() -> string { buf := make([dynamic]u8, MAX_PATH) for { @@ -790,16 +802,19 @@ exit :: proc "contextless" (code: int) -> ! { _unix_exit(c.int(code)) } +@(require_results) current_thread_id :: proc "contextless" () -> int { return _unix_getthrid() } +@(require_results) dlopen :: proc(filename: string, flags: int) -> rawptr { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(filename, context.temp_allocator) handle := _unix_dlopen(cstr, c.int(flags)) return handle } +@(require_results) dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil) runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() @@ -811,10 +826,12 @@ dlclose :: proc(handle: rawptr) -> bool { assert(handle != nil) return _unix_dlclose(handle) == 0 } +@(require_results) dlerror :: proc() -> string { return string(_unix_dlerror()) } +@(require_results) get_page_size :: proc() -> int { // NOTE(tetra): The page size never changes, so why do anything complicated // if we don't have to. @@ -829,11 +846,12 @@ get_page_size :: proc() -> int { _SC_NPROCESSORS_ONLN :: 503 -@(private) +@(private, require_results) _processor_core_count :: proc() -> int { return int(_sysconf(_SC_NPROCESSORS_ONLN)) } +@(require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 992c00f21..28f470357 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -27,6 +27,7 @@ stderr: Handle = 2 args := _alloc_command_line_arguments() +@(require_results) _alloc_command_line_arguments :: proc() -> (args: []string) { args = make([]string, len(runtime.args__)) for &arg, i in args { @@ -91,8 +92,9 @@ init_preopens :: proc() { preopens = dyn_preopens[:] } +@(require_results) wasi_match_preopen :: proc(path: string) -> (wasi.fd_t, string, bool) { - + @(require_results) prefix_matches :: proc(prefix, path: string) -> bool { // Empty is valid for any relative path. if len(prefix) == 0 && len(path) > 0 && path[0] != '/' { @@ -163,6 +165,7 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { n, err := wasi.fd_pread(wasi.fd_t(fd), {iovs}, wasi.filesize_t(offset)) return int(n), Platform_Error(err) } +@(require_results) open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) { oflags: wasi.oflags_t if mode & O_CREATE == O_CREATE { @@ -215,14 +218,16 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { n, err := wasi.fd_seek(wasi.fd_t(fd), wasi.filedelta_t(offset), wasi.whence_t(whence)) return i64(n), Platform_Error(err) } +@(require_results) current_thread_id :: proc "contextless" () -> int { return 0 } -@(private) +@(private, require_results) _processor_core_count :: proc() -> int { return 1 } +@(require_results) file_size :: proc(fd: Handle) -> (size: i64, err: Errno) { stat := wasi.fd_filestat_get(wasi.fd_t(fd)) or_return size = i64(stat.size) diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 5a080e18c..273fe5af0 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -153,7 +153,7 @@ get_page_size :: proc() -> int { return page_size } -@(private) +@(private, require_results) _processor_core_count :: proc() -> int { length : win32.DWORD = 0 result := win32.GetLogicalProcessorInformation(nil, &length) @@ -184,12 +184,14 @@ exit :: proc "contextless" (code: int) -> ! { +@(require_results) current_thread_id :: proc "contextless" () -> int { return int(win32.GetCurrentThreadId()) } +@(require_results) _alloc_command_line_arguments :: proc() -> []string { arg_count: i32 arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count) @@ -223,44 +225,52 @@ _alloc_command_line_arguments :: proc() -> []string { */ WINDOWS_11_BUILD_CUTOFF :: 22_000 -get_windows_version_w :: proc() -> win32.OSVERSIONINFOEXW { +@(require_results) +get_windows_version_w :: proc "contextless" () -> win32.OSVERSIONINFOEXW { osvi : win32.OSVERSIONINFOEXW osvi.dwOSVersionInfoSize = size_of(win32.OSVERSIONINFOEXW) win32.RtlGetVersion(&osvi) return osvi } -is_windows_xp :: proc() -> bool { +@(require_results) +is_windows_xp :: proc "contextless" () -> bool { osvi := get_windows_version_w() return (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) } -is_windows_vista :: proc() -> bool { +@(require_results) +is_windows_vista :: proc "contextless" () -> bool { osvi := get_windows_version_w() return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) } -is_windows_7 :: proc() -> bool { +@(require_results) +is_windows_7 :: proc "contextless" () -> bool { osvi := get_windows_version_w() return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) } -is_windows_8 :: proc() -> bool { +@(require_results) +is_windows_8 :: proc "contextless" () -> bool { osvi := get_windows_version_w() return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) } -is_windows_8_1 :: proc() -> bool { +@(require_results) +is_windows_8_1 :: proc "contextless" () -> bool { osvi := get_windows_version_w() return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) } -is_windows_10 :: proc() -> bool { +@(require_results) +is_windows_10 :: proc "contextless" () -> bool { osvi := get_windows_version_w() return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber < WINDOWS_11_BUILD_CUTOFF) } -is_windows_11 :: proc() -> bool { +@(require_results) +is_windows_11 :: proc "contextless" () -> bool { osvi := get_windows_version_w() return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= WINDOWS_11_BUILD_CUTOFF) } diff --git a/core/os/stat_unix.odin b/core/os/stat_unix.odin index 189f32743..8e89bee4f 100644 --- a/core/os/stat_unix.odin +++ b/core/os/stat_unix.odin @@ -50,14 +50,14 @@ File_Info :: struct { } */ -@private +@(private, require_results) _make_time_from_unix_file_time :: proc(uft: Unix_File_Time) -> time.Time { return time.Time{ _nsec = uft.nanoseconds + uft.seconds * 1_000_000_000, } } -@private +@(private) _fill_file_info_from_stat :: proc(fi: ^File_Info, s: OS_Stat) { fi.size = s.size fi.mode = cast(File_Mode)s.mode @@ -71,7 +71,7 @@ _fill_file_info_from_stat :: proc(fi: ^File_Info, s: OS_Stat) { } -@private +@(private, require_results) path_base :: proc(path: string) -> string { is_separator :: proc(c: byte) -> bool { return c == '/' @@ -100,6 +100,7 @@ path_base :: proc(path: string) -> string { } +@(require_results) lstat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, err: Error) { context.allocator = allocator @@ -110,6 +111,7 @@ lstat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, e return } +@(require_results) stat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, err: Error) { context.allocator = allocator @@ -120,6 +122,7 @@ stat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, er return } +@(require_results) fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err: Error) { context.allocator = allocator diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index 0c0bf51a3..ca4f87668 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -4,7 +4,7 @@ import "core:time" import "base:runtime" import win32 "core:sys/windows" -@(private) +@(private, require_results) full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Errno) { context.allocator = allocator @@ -30,7 +30,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa return } -@(private) +@(private, require_results) _stat :: proc(name: string, create_file_attributes: u32, allocator := context.allocator) -> (fi: File_Info, e: Errno) { if len(name) == 0 { return {}, ERROR_PATH_NOT_FOUND @@ -72,17 +72,20 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al } +@(require_results) lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) { attrs := win32.FILE_FLAG_BACKUP_SEMANTICS attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT return _stat(name, attrs, allocator) } +@(require_results) stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) { attrs := win32.FILE_FLAG_BACKUP_SEMANTICS return _stat(name, attrs, allocator) } +@(require_results) fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err: Errno) { if fd == 0 { err = ERROR_INVALID_HANDLE @@ -108,7 +111,7 @@ fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err } -@(private) +@(private, require_results) cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { buf := buf N := 0 @@ -133,13 +136,13 @@ cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { return buf } -@(private) +@(private, require_results) cleanpath_from_handle :: proc(fd: Handle) -> (s: string, err: Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) buf := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return return win32.utf16_to_utf8(buf, context.allocator) } -@(private) +@(private, require_results) cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ([]u16, Errno) { if fd == 0 { return nil, ERROR_INVALID_HANDLE @@ -154,14 +157,14 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ( buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0) return buf[:buf_len], nil } -@(private) +@(private, require_results) cleanpath_from_buf :: proc(buf: []u16) -> string { buf := buf buf = cleanpath_strip_prefix(buf) return win32.utf16_to_utf8(buf, context.allocator) or_else "" } -@(private) +@(private, require_results) basename :: proc(name: string) -> (base: string) { name := name if len(name) > 3 && name[:3] == `\\?` { @@ -187,7 +190,7 @@ basename :: proc(name: string) -> (base: string) { return name } -@(private) +@(private, require_results) file_type_mode :: proc(h: win32.HANDLE) -> File_Mode { switch win32.GetFileType(h) { case win32.FILE_TYPE_PIPE: @@ -199,7 +202,7 @@ file_type_mode :: proc(h: win32.HANDLE) -> File_Mode { } -@(private) +@(private, require_results) file_mode_from_file_attributes :: proc(FileAttributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (mode: File_Mode) { if FileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 { mode |= 0o444 @@ -236,7 +239,7 @@ windows_set_file_info_times :: proc(fi: ^File_Info, d: ^$T) { fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime)) } -@(private) +@(private, require_results) file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Errno) { fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) @@ -251,7 +254,7 @@ file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_ return } -@(private) +@(private, require_results) file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) -> (fi: File_Info, e: Errno) { fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) @@ -266,7 +269,7 @@ file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) return } -@(private) +@(private, require_results) file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Errno) { d: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(h, &d) { From d0709a7de21efded4625167dbff4a7dd13d561b4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 17:14:24 +0100 Subject: [PATCH 088/122] Allow for nested `temp_allocator()` calls to flip between arenas on `TEMP_ALLOCATOR_GUARD`s --- core/os/os2/allocators.odin | 32 +++++++++++++++++++++++++------- core/os/os2/errors_linux.odin | 8 ++++---- core/os/os2/path_linux.odin | 2 +- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/core/os/os2/allocators.odin b/core/os/os2/allocators.odin index 40672face..f057ea057 100644 --- a/core/os/os2/allocators.odin +++ b/core/os/os2/allocators.odin @@ -10,20 +10,29 @@ file_allocator :: proc() -> runtime.Allocator { temp_allocator_proc :: runtime.arena_allocator_proc +@(private="file") +MAX_TEMP_ARENA_COUNT :: 2 + @(private="file", thread_local) -global_default_temp_allocator_arena: runtime.Arena +global_default_temp_allocator_arenas: [MAX_TEMP_ARENA_COUNT]runtime.Arena + +@(private="file", thread_local) +global_default_temp_allocator_index: uint + @(require_results) temp_allocator :: proc() -> runtime.Allocator { return runtime.Allocator{ procedure = temp_allocator_proc, - data = &global_default_temp_allocator_arena, + data = &global_default_temp_allocator_arenas[global_default_temp_allocator_index], } } + + @(require_results) temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: runtime.Arena_Temp) { - temp = runtime.arena_temp_begin(&global_default_temp_allocator_arena, loc) + temp = runtime.arena_temp_begin(&global_default_temp_allocator_arenas[global_default_temp_allocator_index], loc) return } @@ -33,16 +42,25 @@ temp_allocator_temp_end :: proc(temp: runtime.Arena_Temp, loc := #caller_locatio @(fini, private) temp_allocator_fini :: proc() { - runtime.arena_destroy(&global_default_temp_allocator_arena) - global_default_temp_allocator_arena = {} + for &arena in global_default_temp_allocator_arenas { + runtime.arena_destroy(&arena) + } + global_default_temp_allocator_arenas = {} } -@(deferred_out=temp_allocator_temp_end) +TEMP_ALLOCATOR_GUARD_END :: proc(temp: runtime.Arena_Temp loc := #caller_location) { + runtime.arena_temp_end(temp, loc) + global_default_temp_allocator_index = (global_default_temp_allocator_index-1)%MAX_TEMP_ARENA_COUNT +} + +@(deferred_out=TEMP_ALLOCATOR_GUARD_END) TEMP_ALLOCATOR_GUARD :: #force_inline proc(ignore := false, loc := #caller_location) -> (runtime.Arena_Temp, runtime.Source_Code_Location) { if ignore { return {}, loc } else { - return temp_allocator_temp_begin(loc), loc + tmp := temp_allocator_temp_begin(loc) + global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT + return tmp, loc } } diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin index 28c93cfae..7f28d1c41 100644 --- a/core/os/os2/errors_linux.odin +++ b/core/os/os2/errors_linux.odin @@ -4,7 +4,7 @@ package os2 import "core:sys/linux" @(rodata) -_errno_strings := [linux.Error]string{ +_errno_strings := [linux.Errno]string{ .NONE = "", .EPERM = "Operation not permitted", .ENOENT = "No such file or directory", @@ -142,7 +142,7 @@ _errno_strings := [linux.Error]string{ } -_get_platform_error :: proc(errno: linux.Error) -> Error { +_get_platform_error :: proc(errno: linux.Errno) -> Error { #partial switch errno { case .NONE: return nil @@ -158,8 +158,8 @@ _get_platform_error :: proc(errno: linux.Error) -> Error { } _error_string :: proc(errno: i32) -> string { - if errno >= 0 && errno <= i32(max(linux.Error)) { - return _errno_strings[linux.Error(errno)] + if errno >= 0 && errno <= i32(max(linux.Errno)) { + return _errno_strings[linux.Errno(errno)] } return "Unknown Error" } diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index 62386675d..be60f9b86 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -59,7 +59,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { path_bytes[len(path)] = 0 dfd: linux.Fd - errno: linux.Error + errno: linux.Errno if path_bytes[0] == '/' { dfd, errno = linux.open("/", _OPENDIR_FLAGS) path_bytes = path_bytes[1:] From f19436fb4d272a46f105271488fdb4408eb0cc87 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 17:17:09 +0100 Subject: [PATCH 089/122] Only swap if there was an arena --- core/os/os2/allocators.odin | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/os/os2/allocators.odin b/core/os/os2/allocators.odin index f057ea057..47f12b540 100644 --- a/core/os/os2/allocators.odin +++ b/core/os/os2/allocators.odin @@ -48,9 +48,11 @@ temp_allocator_fini :: proc() { global_default_temp_allocator_arenas = {} } -TEMP_ALLOCATOR_GUARD_END :: proc(temp: runtime.Arena_Temp loc := #caller_location) { +TEMP_ALLOCATOR_GUARD_END :: proc(temp: runtime.Arena_Temp, loc := #caller_location) { runtime.arena_temp_end(temp, loc) - global_default_temp_allocator_index = (global_default_temp_allocator_index-1)%MAX_TEMP_ARENA_COUNT + if temp.arena != nil { + global_default_temp_allocator_index = (global_default_temp_allocator_index-1)%MAX_TEMP_ARENA_COUNT + } } @(deferred_out=TEMP_ALLOCATOR_GUARD_END) From 046f72befd12b03fe4bdcb146e7c1c6797d45e9d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 17:31:39 +0100 Subject: [PATCH 090/122] Mock out `open_buffered` --- core/os/os2/file.odin | 9 ++++ core/os/os2/file_linux.odin | 82 ++++++++++++++++++++++++++++++----- core/os/os2/file_windows.odin | 69 +++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 10 deletions(-) diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index 52fd02478..2c042e0c5 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -104,6 +104,15 @@ open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File, return _open(name, flags, perm) } +@(require_results) +open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (^File, Error) { + if buffer_size == 0 { + return _open(name, flags, perm) + } + return _open_buffered(name, buffer_size, flags, perm) +} + + @(require_results) new_file :: proc(handle: uintptr, name: string) -> ^File { return _new_file(handle, name) or_else panic("Out of memory") diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index d2a7483ca..6b981cca1 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -1,9 +1,10 @@ //+private package os2 +import "base:runtime" import "core:io" import "core:time" -import "base:runtime" +import "core:sync" import "core:sys/linux" File_Impl :: struct { @@ -11,13 +12,17 @@ File_Impl :: struct { name: string, fd: linux.Fd, allocator: runtime.Allocator, + + buffer: []byte, + rw_mutex: sync.RW_Mutex, // read write calls + p_mutex: sync.Mutex, // pread pwrite calls } _stdin := File{ impl = &File_Impl{ name = "/proc/self/fd/0", fd = 0, - allocator = _file_allocator(), + allocator = file_allocator(), }, stream = { procedure = _file_stream_proc, @@ -28,7 +33,7 @@ _stdout := File{ impl = &File_Impl{ name = "/proc/self/fd/1", fd = 1, - allocator = _file_allocator(), + allocator = file_allocator(), }, stream = { procedure = _file_stream_proc, @@ -39,7 +44,7 @@ _stderr := File{ impl = &File_Impl{ name = "/proc/self/fd/2", fd = 2, - allocator = _file_allocator(), + allocator = file_allocator(), }, stream = { procedure = _file_stream_proc, @@ -59,10 +64,6 @@ _standard_stream_init :: proc() { stderr = &_stderr } -_file_allocator :: proc() -> runtime.Allocator { - return heap_allocator() -} - _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return @@ -108,13 +109,30 @@ _new_file :: proc(fd: uintptr, _: string = "") -> (f: ^File, err: Error) { return &impl.file, nil } + +@(require_results) +_open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (f: ^File, err: Error) { + assert(buffer_size > 0) + f, err = _open(name, flags, perm) + if f != nil && err == nil { + impl := (^File_Impl)(f.impl) + impl.buffer = make([]byte, buffer_size, file_allocator()) + f.stream.procedure = _file_stream_buffered_proc + } + return +} + _destroy :: proc(f: ^File_Impl) -> Error { if f == nil { return nil } a := f.allocator - delete(f.name, a) - free(f, a) + err0 := delete(f.name, a) + err1 := delete(f.buffer, a) + err2 := free(f, a) + err0 or_return + err1 or_return + err2 or_return return nil } @@ -463,3 +481,47 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, return 0, .Empty } + +@(private="package") +_file_stream_buffered_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + f := (^File_Impl)(stream_data) + ferr: Error + switch mode { + case .Read: + n, ferr = _read(f, p) + err = error_to_io_error(ferr) + return + case .Read_At: + n, ferr = _read_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Write: + n, ferr = _write(f, p) + err = error_to_io_error(ferr) + return + case .Write_At: + n, ferr = _write_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Seek: + n, ferr = _seek(f, offset, whence) + err = error_to_io_error(ferr) + return + case .Size: + n, ferr = _file_size(f) + err = error_to_io_error(ferr) + return + case .Flush: + ferr = _flush(f) + err = error_to_io_error(ferr) + return + case .Close, .Destroy: + ferr = _close(f) + err = error_to_io_error(ferr) + return + case .Query: + return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query}) + } + return 0, .Empty +} + diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index 48a5427f1..c037e3f93 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -33,6 +33,7 @@ File_Impl :: struct { allocator: runtime.Allocator, + buffer: []byte, rw_mutex: sync.RW_Mutex, // read write calls p_mutex: sync.Mutex, // pread pwrite calls } @@ -165,6 +166,26 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { return &impl.file, nil } + +@(require_results) +_open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (f: ^File, err: Error) { + assert(buffer_size > 0) + flags := flags if flags != nil else {.Read} + handle := _open_internal(name, flags, perm) or_return + return _new_file_buffered(handle, name, buffer_size) +} + +_new_file_buffered :: proc(handle: uintptr, name: string, buffer_size: uint) -> (f: ^File, err: Error) { + f, err = _new_file(handle, name) + if f != nil && err == nil { + impl := (^File_Impl)(f.impl) + impl.buffer = make([]byte, buffer_size, file_allocator()) + f.stream.procedure = _file_stream_buffered_proc + } + return +} + + _fd :: proc(f: ^File) -> uintptr { if f == nil || f.impl == nil { return INVALID_HANDLE @@ -181,9 +202,11 @@ _destroy :: proc(f: ^File_Impl) -> Error { err0 := free(f.wname, a) err1 := delete(f.name, a) err2 := free(f, a) + err3 := delete(f.buffer, a) err0 or_return err1 or_return err2 or_return + err3 or_return return nil } @@ -780,6 +803,52 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, } +@(private="package") +_file_stream_buffered_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + f := (^File_Impl)(stream_data) + ferr: Error + switch mode { + case .Read: + n, ferr = _read(f, p) + err = error_to_io_error(ferr) + return + case .Read_At: + n, ferr = _read_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Write: + n, ferr = _write(f, p) + err = error_to_io_error(ferr) + return + case .Write_At: + n, ferr = _write_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Seek: + n, ferr = _seek(f, offset, whence) + err = error_to_io_error(ferr) + return + case .Size: + n, ferr = _file_size(f) + err = error_to_io_error(ferr) + return + case .Flush: + ferr = _flush(f) + err = error_to_io_error(ferr) + return + case .Close, .Destroy: + ferr = _close(f) + err = error_to_io_error(ferr) + return + case .Query: + return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Query}) + } + return 0, .Empty +} + + + + @(private="package", require_results) win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: [^]u16, err: runtime.Allocator_Error) { From cf3c1a85ec601f6814460bd2317dcdf91f7c7665 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 17:36:28 +0100 Subject: [PATCH 091/122] Remove `temp` parameter --- core/os/os2/allocators.odin | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/core/os/os2/allocators.odin b/core/os/os2/allocators.odin index 47f12b540..ef73809b1 100644 --- a/core/os/os2/allocators.odin +++ b/core/os/os2/allocators.odin @@ -56,13 +56,9 @@ TEMP_ALLOCATOR_GUARD_END :: proc(temp: runtime.Arena_Temp, loc := #caller_locati } @(deferred_out=TEMP_ALLOCATOR_GUARD_END) -TEMP_ALLOCATOR_GUARD :: #force_inline proc(ignore := false, loc := #caller_location) -> (runtime.Arena_Temp, runtime.Source_Code_Location) { - if ignore { - return {}, loc - } else { - tmp := temp_allocator_temp_begin(loc) - global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT - return tmp, loc - } +TEMP_ALLOCATOR_GUARD :: #force_inline proc(loc := #caller_location) -> (runtime.Arena_Temp, runtime.Source_Code_Location) { + tmp := temp_allocator_temp_begin(loc) + global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT + return tmp, loc } From 60bc7f53d227790b7aa342eb6728bbeeb1bf669f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 17:41:48 +0100 Subject: [PATCH 092/122] Comment out `open_buffered` --- core/os/os2/file.odin | 14 +++---- core/os/os2/file_windows.odin | 69 ++++++++++------------------------- 2 files changed, 27 insertions(+), 56 deletions(-) diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index 2c042e0c5..454bc50b9 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -104,13 +104,13 @@ open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File, return _open(name, flags, perm) } -@(require_results) -open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (^File, Error) { - if buffer_size == 0 { - return _open(name, flags, perm) - } - return _open_buffered(name, buffer_size, flags, perm) -} +// @(require_results) +// open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (^File, Error) { +// if buffer_size == 0 { +// return _open(name, flags, perm) +// } +// return _open_buffered(name, buffer_size, flags, perm) +// } @(require_results) diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index c037e3f93..74067464b 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -33,7 +33,11 @@ File_Impl :: struct { allocator: runtime.Allocator, - buffer: []byte, + r_buf: []byte, + w_buf: []byte, + w_n: int, + max_consecutive_empty_writes: int, + rw_mutex: sync.RW_Mutex, // read write calls p_mutex: sync.Mutex, // pread pwrite calls } @@ -179,8 +183,8 @@ _new_file_buffered :: proc(handle: uintptr, name: string, buffer_size: uint) -> f, err = _new_file(handle, name) if f != nil && err == nil { impl := (^File_Impl)(f.impl) - impl.buffer = make([]byte, buffer_size, file_allocator()) - f.stream.procedure = _file_stream_buffered_proc + impl.r_buf = make([]byte, buffer_size, file_allocator()) + impl.w_buf = make([]byte, buffer_size, file_allocator()) } return } @@ -202,11 +206,13 @@ _destroy :: proc(f: ^File_Impl) -> Error { err0 := free(f.wname, a) err1 := delete(f.name, a) err2 := free(f, a) - err3 := delete(f.buffer, a) + err3 := delete(f.r_buf, a) + err4 := delete(f.w_buf, a) err0 or_return err1 or_return err2 or_return err3 or_return + err4 or_return return nil } @@ -254,6 +260,10 @@ _seek :: proc(f: ^File_Impl, offset: i64, whence: io.Seek_From) -> (ret: i64, er } _read :: proc(f: ^File_Impl, p: []byte) -> (n: i64, err: Error) { + return _read_internal(f, p) +} + +_read_internal :: proc(f: ^File_Impl, p: []byte) -> (n: i64, err: Error) { read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Error) { if len(b) == 0 { return 0, nil @@ -375,6 +385,9 @@ _read_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (n: i64, err: Error) } _write :: proc(f: ^File_Impl, p: []byte) -> (n: i64, err: Error) { + return _write_internal(f, p) +} +_write_internal :: proc(f: ^File_Impl, p: []byte) -> (n: i64, err: Error) { if len(p) == 0 { return } @@ -459,6 +472,9 @@ _sync :: proc(f: ^File) -> Error { } _flush :: proc(f: ^File_Impl) -> Error { + return _flush(f) +} +_flush_internal :: proc(f: ^File_Impl) -> Error { handle := _handle(&f.file) if !win32.FlushFileBuffers(handle) { return _get_platform_error() @@ -803,51 +819,6 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, } -@(private="package") -_file_stream_buffered_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { - f := (^File_Impl)(stream_data) - ferr: Error - switch mode { - case .Read: - n, ferr = _read(f, p) - err = error_to_io_error(ferr) - return - case .Read_At: - n, ferr = _read_at(f, p, offset) - err = error_to_io_error(ferr) - return - case .Write: - n, ferr = _write(f, p) - err = error_to_io_error(ferr) - return - case .Write_At: - n, ferr = _write_at(f, p, offset) - err = error_to_io_error(ferr) - return - case .Seek: - n, ferr = _seek(f, offset, whence) - err = error_to_io_error(ferr) - return - case .Size: - n, ferr = _file_size(f) - err = error_to_io_error(ferr) - return - case .Flush: - ferr = _flush(f) - err = error_to_io_error(ferr) - return - case .Close, .Destroy: - ferr = _close(f) - err = error_to_io_error(ferr) - return - case .Query: - return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Query}) - } - return 0, .Empty -} - - - @(private="package", require_results) From 7e0fa795e4cb86300bf324f6e0f59279578eefe1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 21:17:58 +0100 Subject: [PATCH 093/122] Just compare against `nil` directly if the comparator is known to be `nil` too --- src/llvm_backend_expr.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 4bb2676d1..1f0719e13 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2524,9 +2524,16 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left if (are_types_identical(a, b)) { // NOTE(bill): No need for a conversion } else if (lb_is_const(left) || lb_is_const_nil(left)) { + if (lb_is_const_nil(left)) { + return lb_emit_comp_against_nil(p, op_kind, right); + } left = lb_emit_conv(p, left, right.type); } else if (lb_is_const(right) || lb_is_const_nil(right)) { + if (lb_is_const_nil(right)) { + return lb_emit_comp_against_nil(p, op_kind, left); + } right = lb_emit_conv(p, right, left.type); + } else { Type *lt = left.type; Type *rt = right.type; From a06cb8ba46e8a116c8968565eef055fc56ec298e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 12:04:36 +0100 Subject: [PATCH 094/122] Add `#simd[N]rawptr` support --- src/check_type.cpp | 2 +- src/types.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 428fe8451..41de8ccce 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -3171,7 +3171,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t } else if (name == "simd") { if (!is_type_valid_vector_elem(elem) && !is_type_polymorphic(elem)) { gbString str = type_to_string(elem); - error(at->elem, "Invalid element type for #simd, expected an integer, float, or boolean with no specific endianness, got '%s'", str); + error(at->elem, "Invalid element type for #simd, expected an integer, float, boolean, or 'rawptr' with no specific endianness, got '%s'", str); gb_string_free(str); *type = alloc_type_array(elem, count, generic_type); return; diff --git a/src/types.cpp b/src/types.cpp index 944760142..da5099d22 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2091,6 +2091,9 @@ gb_internal bool is_type_valid_vector_elem(Type *t) { if (is_type_boolean(t)) { return true; } + if (t->Basic.kind == Basic_rawptr) { + return true; + } } return false; } From fd06be2243db3fa193702f881947eaa5f2ebf24b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 12:33:02 +0100 Subject: [PATCH 095/122] Allow `swizzle` to take more arguments than the original array length --- src/check_builtin.cpp | 2 +- src/llvm_backend_expr.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b6b1f9874..b96337326 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2460,7 +2460,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As arg_count++; } - if (arg_count > max_count) { + if (false && arg_count > max_count) { error(call, "Too many 'swizzle' indices, %td > %td", arg_count, max_count); return false; } else if (arg_count < 2) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 1f0719e13..59d5cce23 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3814,7 +3814,7 @@ gb_internal lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, Type *type = base_type(lb_addr_type(addr)); GB_ASSERT(type->kind == Type_Array); i64 count = type->Array.count; - if (count <= 4) { + if (count <= 4 && index_count <= 4) { u8 indices[4] = {}; u8 index_count = 0; for (i32 i = 1; i < ce->args.count; i++) { From eeb92e2644a8241b6dc6950f6a2712d5164ea4e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 13:06:55 +0100 Subject: [PATCH 096/122] Allow cast between `#simd[N]rawptr` <-> `#simd[N]uintptr` --- src/llvm_backend_expr.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 59d5cce23..f843dfa92 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2028,7 +2028,11 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } else if (is_type_integer(src_elem) && is_type_boolean(dst_elem)) { LLVMValueRef i1vector = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(LLVMTypeOf(value.value)), ""); res.value = LLVMBuildIntCast2(p->builder, i1vector, lb_type(m, t), !is_type_unsigned(src_elem), ""); - } else { + } else if (is_type_pointer(src_elem) && is_type_integer(dst_elem)) { + res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); + } else if (is_type_integer(src_elem) && is_type_pointer(dst_elem)) { + res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); + }else { GB_PANIC("Unhandled simd vector conversion: %s -> %s", type_to_string(src), type_to_string(dst)); } return res; From 9a01a13914e9b1f577399fed7ed09132306946b1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 13:13:19 +0100 Subject: [PATCH 097/122] Add `simd_reduce_any` and `simd_reduce_all` --- base/intrinsics/intrinsics.odin | 18 +++++++++++------- core/simd/simd.odin | 3 +++ src/check_builtin.cpp | 23 +++++++++++++++++++++++ src/checker_builtin_procs.hpp | 7 +++++++ src/llvm_backend_proc.cpp | 17 +++++++++++++++++ 5 files changed, 61 insertions(+), 7 deletions(-) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 37a42b904..277eafdf1 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -268,13 +268,17 @@ simd_lanes_ge :: proc(a, b: #simd[N]T) -> #simd[N]Integer --- simd_extract :: proc(a: #simd[N]T, idx: uint) -> T --- simd_replace :: proc(a: #simd[N]T, idx: uint, elem: T) -> #simd[N]T --- -simd_reduce_add_ordered :: proc(a: #simd[N]T) -> T --- -simd_reduce_mul_ordered :: proc(a: #simd[N]T) -> T --- -simd_reduce_min :: proc(a: #simd[N]T) -> T --- -simd_reduce_max :: proc(a: #simd[N]T) -> T --- -simd_reduce_and :: proc(a: #simd[N]T) -> T --- -simd_reduce_or :: proc(a: #simd[N]T) -> T --- -simd_reduce_xor :: proc(a: #simd[N]T) -> T --- +simd_reduce_add_ordered :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_mul_ordered :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_min :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_max :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_and :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_or :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_xor :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- + +simd_reduce_any :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- +simd_reduce_all :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- + simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T --- simd_select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index c5a594df6..6166f703b 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -115,6 +115,9 @@ reduce_and :: intrinsics.simd_reduce_and reduce_or :: intrinsics.simd_reduce_or reduce_xor :: intrinsics.simd_reduce_xor +reduce_any :: intrinsics.simd_reduce_any +reduce_all :: intrinsics.simd_reduce_all + // swizzle :: proc(a: #simd[N]T, indices: ..int) -> #simd[len(indices)]T swizzle :: builtin.swizzle diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b96337326..73a90ed62 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -775,6 +775,29 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return true; } + case BuiltinProc_simd_reduce_any: + case BuiltinProc_simd_reduce_all: + { + Operand x = {}; + check_expr(c, &x, ce->args[0]); if (x.mode == Addressing_Invalid) return false; + + if (!is_type_simd_vector(x.type)) { + error(x.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); + return false; + } + Type *elem = base_array_type(x.type); + if (!is_type_boolean(elem)) { + gbString xs = type_to_string(x.type); + error(x.expr, "'%.*s' expected a #simd type with a boolean element, got '%s'", LIT(builtin_name), xs); + gb_string_free(xs); + return false; + } + + operand->mode = Addressing_Value; + operand->type = t_untyped_bool; + return true; + } + case BuiltinProc_simd_shuffle: { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 3a2e1ce22..b6eb326d2 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -174,6 +174,9 @@ BuiltinProc__simd_begin, BuiltinProc_simd_reduce_or, BuiltinProc_simd_reduce_xor, + BuiltinProc_simd_reduce_any, + BuiltinProc_simd_reduce_all, + BuiltinProc_simd_shuffle, BuiltinProc_simd_select, @@ -501,6 +504,10 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_reduce_or"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_reduce_xor"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_reduce_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_reduce_all"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("simd_shuffle"), 2, true, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_select"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 2f736ff6c..ee121d6f2 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1527,6 +1527,23 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn return res; } + case BuiltinProc_simd_reduce_any: + case BuiltinProc_simd_reduce_all: + { + char const *name = nullptr; + switch (builtin_id) { + case BuiltinProc_simd_reduce_any: name = "llvm.vector.reduce.and"; break; + case BuiltinProc_simd_reduce_all: name = "llvm.vector.reduce.or"; break; + } + + LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) }; + LLVMValueRef args[1] = { arg0.value }; + + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + return res; + } + + case BuiltinProc_simd_shuffle: { Type *vt = arg0.type; From 90fc52c2ee2ac3e5c01744f57d1e02a30e19b55a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 13:19:01 +0100 Subject: [PATCH 098/122] Rename `add_sat` -> `saturating_add` --- base/intrinsics/intrinsics.odin | 7 +++++-- core/simd/simd.odin | 4 ++-- src/check_builtin.cpp | 12 ++++++------ src/checker_builtin_procs.hpp | 16 ++++++++-------- src/llvm_backend_proc.cpp | 20 ++++++++++---------- 5 files changed, 31 insertions(+), 28 deletions(-) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 277eafdf1..fadbda3fb 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -42,8 +42,8 @@ overflow_add :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) #option overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) #optional_ok --- overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) #optional_ok --- -add_sat :: proc(lhs, rhs: $T) -> T where type_is_integer(T) --- -sub_sat :: proc(lhs, rhs: $T) -> T where type_is_integer(T) --- +saturating_add :: proc(lhs, rhs: $T) -> T where type_is_integer(T) --- +saturating_sub :: proc(lhs, rhs: $T) -> T where type_is_integer(T) --- sqrt :: proc(x: $T) -> T where type_is_float(T) || (type_is_simd_vector(T) && type_is_float(type_elem_type(T))) --- @@ -227,6 +227,9 @@ simd_sub :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_mul :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_div :: proc(a, b: #simd[N]T) -> #simd[N]T where type_is_float(T) --- +simd_saturating_add :: proc(a, b: #simd[N]T) -> #simd[N]T where type_is_integer(T) --- +simd_saturating_sub :: proc(a, b: #simd[N]T) -> #simd[N]T where type_is_integer(T) --- + // Keeps Odin's Behaviour // (x << y) if y <= mask else 0 simd_shl :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 6166f703b..46f6a0112 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -74,8 +74,8 @@ shl_masked :: intrinsics.simd_shl_masked shr_masked :: intrinsics.simd_shr_masked // Saturation Arithmetic -add_sat :: intrinsics.simd_add_sat -sub_sat :: intrinsics.simd_sub_sat +saturating_add :: intrinsics.simd_saturating_add +saturating_sub :: intrinsics.simd_saturating_sub bit_and :: intrinsics.simd_bit_and bit_or :: intrinsics.simd_bit_or diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 73a90ed62..b4967a56a 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -470,8 +470,8 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan } // Integer only - case BuiltinProc_simd_add_sat: - case BuiltinProc_simd_sub_sat: + case BuiltinProc_simd_saturating_add: + case BuiltinProc_simd_saturating_sub: case BuiltinProc_simd_bit_and: case BuiltinProc_simd_bit_or: case BuiltinProc_simd_bit_xor: @@ -501,8 +501,8 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan Type *elem = base_array_type(x.type); switch (id) { - case BuiltinProc_simd_add_sat: - case BuiltinProc_simd_sub_sat: + case BuiltinProc_simd_saturating_add: + case BuiltinProc_simd_saturating_sub: if (!is_type_integer(elem)) { gbString xs = type_to_string(x.type); error(x.expr, "'%.*s' expected a #simd type with an integer element, got '%s'", LIT(builtin_name), xs); @@ -4325,8 +4325,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_add_sat: - case BuiltinProc_sub_sat: + case BuiltinProc_saturating_add: + case BuiltinProc_saturating_sub: { Operand x = {}; Operand y = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index b6eb326d2..7fd71c36a 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -70,8 +70,8 @@ enum BuiltinProcId { BuiltinProc_overflow_sub, BuiltinProc_overflow_mul, - BuiltinProc_add_sat, - BuiltinProc_sub_sat, + BuiltinProc_saturating_add, + BuiltinProc_saturating_sub, BuiltinProc_sqrt, BuiltinProc_fused_mul_add, @@ -141,8 +141,8 @@ BuiltinProc__simd_begin, BuiltinProc_simd_shl_masked, // C logic BuiltinProc_simd_shr_masked, // C logic - BuiltinProc_simd_add_sat, // saturation arithmetic - BuiltinProc_simd_sub_sat, // saturation arithmetic + BuiltinProc_simd_saturating_add, // saturation arithmetic + BuiltinProc_simd_saturating_sub, // saturation arithmetic BuiltinProc_simd_bit_and, BuiltinProc_simd_bit_or, @@ -399,8 +399,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("overflow_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("overflow_mul"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("add_sat"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("sub_sat"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("saturating_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("saturating_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("sqrt"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fused_mul_add"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -470,8 +470,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_shl_masked"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_shr_masked"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("simd_add_sat"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("simd_sub_sat"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_saturating_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_saturating_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_bit_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_bit_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ee121d6f2..64db2ad36 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1646,13 +1646,13 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn } - case BuiltinProc_simd_add_sat: - case BuiltinProc_simd_sub_sat: + case BuiltinProc_simd_saturating_add: + case BuiltinProc_simd_saturating_sub: { char const *name = nullptr; switch (builtin_id) { - case BuiltinProc_simd_add_sat: name = is_signed ? "llvm.sadd.sat" : "llvm.uadd.sat"; break; - case BuiltinProc_simd_sub_sat: name = is_signed ? "llvm.ssub.sat" : "llvm.usub.sat"; break; + case BuiltinProc_simd_saturating_add: name = is_signed ? "llvm.sadd.sat" : "llvm.uadd.sat"; break; + case BuiltinProc_simd_saturating_sub: name = is_signed ? "llvm.ssub.sat" : "llvm.usub.sat"; break; } LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)}; @@ -2302,8 +2302,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu return res; } - case BuiltinProc_add_sat: - case BuiltinProc_sub_sat: + case BuiltinProc_saturating_add: + case BuiltinProc_saturating_sub: { Type *main_type = tv.type; Type *type = main_type; @@ -2316,13 +2316,13 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu char const *name = nullptr; if (is_type_unsigned(type)) { switch (id) { - case BuiltinProc_add_sat: name = "llvm.uadd.sat"; break; - case BuiltinProc_sub_sat: name = "llvm.usub.sat"; break; + case BuiltinProc_saturating_add: name = "llvm.uadd.sat"; break; + case BuiltinProc_saturating_sub: name = "llvm.usub.sat"; break; } } else { switch (id) { - case BuiltinProc_add_sat: name = "llvm.sadd.sat"; break; - case BuiltinProc_sub_sat: name = "llvm.ssub.sat"; break; + case BuiltinProc_saturating_add: name = "llvm.sadd.sat"; break; + case BuiltinProc_saturating_sub: name = "llvm.ssub.sat"; break; } } LLVMTypeRef types[1] = {lb_type(p->module, type)}; From b67ed78afdbe9a9b3330f07d4d55ca7604ec930e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 13:21:27 +0100 Subject: [PATCH 099/122] `add_sat` -> `saturating_add` --- core/simd/x86/sse2.odin | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/simd/x86/sse2.odin b/core/simd/x86/sse2.odin index 426359031..2e3eb8523 100644 --- a/core/simd/x86/sse2.odin +++ b/core/simd/x86/sse2.odin @@ -39,19 +39,19 @@ _mm_add_epi64 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { } @(require_results, enable_target_feature="sse2") _mm_adds_epi8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.add_sat(transmute(i8x16)a, transmute(i8x16)b) + return transmute(__m128i)simd.saturating_add(transmute(i8x16)a, transmute(i8x16)b) } @(require_results, enable_target_feature="sse2") _mm_adds_epi16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.add_sat(transmute(i16x8)a, transmute(i16x8)b) + return transmute(__m128i)simd.saturating_add(transmute(i16x8)a, transmute(i16x8)b) } @(require_results, enable_target_feature="sse2") _mm_adds_epu8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.add_sat(transmute(u8x16)a, transmute(u8x16)b) + return transmute(__m128i)simd.saturating_add(transmute(u8x16)a, transmute(u8x16)b) } @(require_results, enable_target_feature="sse2") _mm_adds_epu16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.add_sat(transmute(u16x8)a, transmute(u16x8)b) + return transmute(__m128i)simd.saturating_add(transmute(u16x8)a, transmute(u16x8)b) } @(require_results, enable_target_feature="sse2") _mm_avg_epu8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { @@ -122,19 +122,19 @@ _mm_sub_epi64 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { } @(require_results, enable_target_feature="sse2") _mm_subs_epi8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.sub_sat(transmute(i8x16)a, transmute(i8x16)b) + return transmute(__m128i)simd.saturating_sub(transmute(i8x16)a, transmute(i8x16)b) } @(require_results, enable_target_feature="sse2") _mm_subs_epi16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.sub_sat(transmute(i16x8)a, transmute(i16x8)b) + return transmute(__m128i)simd.saturating_sub(transmute(i16x8)a, transmute(i16x8)b) } @(require_results, enable_target_feature="sse2") _mm_subs_epu8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.sub_sat(transmute(u8x16)a, transmute(u8x16)b) + return transmute(__m128i)simd.saturating_sub(transmute(u8x16)a, transmute(u8x16)b) } @(require_results, enable_target_feature="sse2") _mm_subs_epu16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.sub_sat(transmute(u16x8)a, transmute(u16x8)b) + return transmute(__m128i)simd.saturating_sub(transmute(u16x8)a, transmute(u16x8)b) } From 7e701d1677fbe594e0970824062d8b3564d33d26 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 13:46:24 +0100 Subject: [PATCH 100/122] Add `intrinsics.simd_gather` and ``intrinsics.simd_scatter` --- base/intrinsics/intrinsics.odin | 4 +++ core/simd/simd.odin | 5 +++ src/check_builtin.cpp | 54 +++++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 6 ++++ src/llvm_backend_proc.cpp | 46 ++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index fadbda3fb..5566c8c6c 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -283,6 +283,10 @@ simd_reduce_any :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- simd_reduce_all :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- +simd_gather :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- +simd_scatter :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- + + simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T --- simd_select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 46f6a0112..2fc0bc2c0 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -102,6 +102,11 @@ lanes_le :: intrinsics.simd_lanes_le lanes_gt :: intrinsics.simd_lanes_gt lanes_ge :: intrinsics.simd_lanes_ge + +// Gather and Scatter intrinsics +gather :: intrinsics.simd_gather +scatter :: intrinsics.simd_scatter + // extract :: proc(a: #simd[N]T, idx: uint) -> T extract :: intrinsics.simd_extract // replace :: proc(a: #simd[N]T, idx: uint, elem: T) -> #simd[N]T diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b4967a56a..99a989b4f 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -663,6 +663,60 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return true; } + case BuiltinProc_simd_gather: + case BuiltinProc_simd_scatter: + { + // gather (ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T + // scatter(ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) + + Operand ptr = {}; + Operand values = {}; + Operand mask = {}; + check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false; + check_expr(c, &values, ce->args[1]); if (values.mode == Addressing_Invalid) return false; + check_expr(c, &mask, ce->args[2]); if (mask.mode == Addressing_Invalid) return false; + if (!is_type_simd_vector(ptr.type)) { error(ptr.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } + if (!is_type_simd_vector(values.type)) { error(values.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } + if (!is_type_simd_vector(mask.type)) { error(mask.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } + + Type *ptr_elem = base_array_type(ptr.type); + if (!is_type_rawptr(ptr_elem)) { + gbString s = type_to_string(ptr.type); + error(ptr.expr, "Expected a simd vector of 'rawptr' for the addresses, got %s", s); + gb_string_free(s); + return false; + } + Type *mask_elem = base_array_type(mask.type); + + if (!is_type_integer(mask_elem) && !is_type_boolean(mask_elem)) { + gbString s = type_to_string(mask.type); + error(mask.expr, "Expected a simd vector of integers or booleans for the mask, got %s", s); + gb_string_free(s); + return false; + } + + i64 ptr_count = get_array_type_count(ptr.type); + i64 values_count = get_array_type_count(values.type); + i64 mask_count = get_array_type_count(mask.type); + if (ptr_count != values_count || + values_count != mask_count || + mask_count != ptr_count) { + gbString s = type_to_string(mask.type); + error(mask.expr, "All simd vectors must be of the same length, got %lld vs %lld vs %lld", cast(long long)ptr_count, cast(long long)values_count, cast(long long)mask_count); + gb_string_free(s); + return false; + } + + if (id == BuiltinProc_simd_gather) { + operand->mode = Addressing_Value; + operand->type = values.type; + } else { + operand->mode = Addressing_NoValue; + operand->type = nullptr; + } + return true; + } + case BuiltinProc_simd_extract: { Operand x = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 7fd71c36a..826c10e10 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -191,6 +191,9 @@ BuiltinProc__simd_begin, BuiltinProc_simd_lanes_rotate_left, BuiltinProc_simd_lanes_rotate_right, + BuiltinProc_simd_gather, + BuiltinProc_simd_scatter, + // Platform specific SIMD intrinsics BuiltinProc_simd_x86__MM_SHUFFLE, @@ -522,6 +525,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_lanes_rotate_left"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_lanes_rotate_right"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_gather"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_scatter"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_x86__MM_SHUFFLE"), 4, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 64db2ad36..5ccbd3399 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1688,6 +1688,52 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn return res; } + + case BuiltinProc_simd_gather: + case BuiltinProc_simd_scatter: + { + LLVMValueRef ptr = arg0.value; + LLVMValueRef val = arg1.value; + LLVMValueRef mask = arg2.value; + + unsigned count = cast(unsigned)get_array_type_count(arg0.type); + + LLVMTypeRef mask_type = LLVMVectorType(LLVMInt1TypeInContext(p->module->ctx), count); + mask = LLVMBuildTrunc(p->builder, mask, mask_type, ""); + + char const *name = nullptr; + switch (builtin_id) { + case BuiltinProc_simd_gather: name = "llvm.masked.gather"; break; + case BuiltinProc_simd_scatter: name = "llvm.masked.scatter"; break; + } + LLVMTypeRef types[2] = { + lb_type(p->module, arg1.type), + lb_type(p->module, arg0.type) + }; + + auto alignment = cast(unsigned long long)type_align_of(base_array_type(arg1.type)); + LLVMValueRef align = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), alignment, false); + + LLVMValueRef args[4] = {}; + switch (builtin_id) { + case BuiltinProc_simd_gather: + args[0] = ptr; + args[1] = align; + args[2] = mask; + args[3] = val; + break; + case BuiltinProc_simd_scatter: + args[0] = val; + args[1] = ptr; + args[2] = align; + args[3] = mask; + break; + } + + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + return res; + + } } GB_PANIC("Unhandled simd intrinsic: '%.*s'", LIT(builtin_procs[builtin_id].name)); From 84ac56f77881c38762ad1a3cf66d4340c8d847d8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 14:08:41 +0100 Subject: [PATCH 101/122] Add `intrinsics.simd_masked_load` and `intrinsics.simd_masked_store` --- base/intrinsics/intrinsics.odin | 7 ++-- core/simd/simd.odin | 3 ++ src/check_builtin.cpp | 62 +++++++++++++++++++++++---------- src/checker.cpp | 4 +-- src/checker_builtin_procs.hpp | 9 +++-- src/llvm_backend_proc.cpp | 18 ++++++++-- 6 files changed, 75 insertions(+), 28 deletions(-) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 5566c8c6c..7aa56a9e9 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -283,8 +283,11 @@ simd_reduce_any :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- simd_reduce_all :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- -simd_gather :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- -simd_scatter :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- +simd_gather :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- +simd_scatter :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- + +simd_masked_load :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- +simd_masked_store :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 2fc0bc2c0..f8924e5de 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -106,6 +106,9 @@ lanes_ge :: intrinsics.simd_lanes_ge // Gather and Scatter intrinsics gather :: intrinsics.simd_gather scatter :: intrinsics.simd_scatter +masked_load :: intrinsics.simd_gather +masked_store :: intrinsics.simd_scatter + // extract :: proc(a: #simd[N]T, idx: uint) -> T extract :: intrinsics.simd_extract diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 99a989b4f..b5851bc01 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -665,26 +665,40 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan case BuiltinProc_simd_gather: case BuiltinProc_simd_scatter: + case BuiltinProc_simd_masked_load: + case BuiltinProc_simd_masked_store: { // gather (ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T // scatter(ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) + // masked_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T + // masked_store(ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) + Operand ptr = {}; Operand values = {}; Operand mask = {}; check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false; check_expr(c, &values, ce->args[1]); if (values.mode == Addressing_Invalid) return false; check_expr(c, &mask, ce->args[2]); if (mask.mode == Addressing_Invalid) return false; - if (!is_type_simd_vector(ptr.type)) { error(ptr.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } if (!is_type_simd_vector(values.type)) { error(values.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } if (!is_type_simd_vector(mask.type)) { error(mask.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } - Type *ptr_elem = base_array_type(ptr.type); - if (!is_type_rawptr(ptr_elem)) { - gbString s = type_to_string(ptr.type); - error(ptr.expr, "Expected a simd vector of 'rawptr' for the addresses, got %s", s); - gb_string_free(s); - return false; + if (id == BuiltinProc_simd_gather || id == BuiltinProc_simd_scatter) { + if (!is_type_simd_vector(ptr.type)) { error(ptr.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } + Type *ptr_elem = base_array_type(ptr.type); + if (!is_type_rawptr(ptr_elem)) { + gbString s = type_to_string(ptr.type); + error(ptr.expr, "Expected a simd vector of 'rawptr' for the addresses, got %s", s); + gb_string_free(s); + return false; + } + } else { + if (!is_type_pointer(ptr.type)) { + gbString s = type_to_string(ptr.type); + error(ptr.expr, "Expected a pointer type for the address, got %s", s); + gb_string_free(s); + return false; + } } Type *mask_elem = base_array_type(mask.type); @@ -695,19 +709,31 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return false; } - i64 ptr_count = get_array_type_count(ptr.type); - i64 values_count = get_array_type_count(values.type); - i64 mask_count = get_array_type_count(mask.type); - if (ptr_count != values_count || - values_count != mask_count || - mask_count != ptr_count) { - gbString s = type_to_string(mask.type); - error(mask.expr, "All simd vectors must be of the same length, got %lld vs %lld vs %lld", cast(long long)ptr_count, cast(long long)values_count, cast(long long)mask_count); - gb_string_free(s); - return false; + if (id == BuiltinProc_simd_gather || id == BuiltinProc_simd_scatter) { + i64 ptr_count = get_array_type_count(ptr.type); + i64 values_count = get_array_type_count(values.type); + i64 mask_count = get_array_type_count(mask.type); + if (ptr_count != values_count || + values_count != mask_count || + mask_count != ptr_count) { + gbString s = type_to_string(mask.type); + error(mask.expr, "All simd vectors must be of the same length, got %lld vs %lld vs %lld", cast(long long)ptr_count, cast(long long)values_count, cast(long long)mask_count); + gb_string_free(s); + return false; + } + } else { + i64 values_count = get_array_type_count(values.type); + i64 mask_count = get_array_type_count(mask.type); + if (values_count != mask_count) { + gbString s = type_to_string(mask.type); + error(mask.expr, "All simd vectors must be of the same length, got %lld vs %lld", cast(long long)values_count, cast(long long)mask_count); + gb_string_free(s); + return false; + } } - if (id == BuiltinProc_simd_gather) { + if (id == BuiltinProc_simd_gather || + id == BuiltinProc_simd_masked_load) { operand->mode = Addressing_Value; operand->type = values.type; } else { diff --git a/src/checker.cpp b/src/checker.cpp index 3eae271a0..60000ec29 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1651,9 +1651,9 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo if (mode == Addressing_Constant || mode == Addressing_Invalid) { expr->tav.value = value; - } else if (mode == Addressing_Value && is_type_typeid(type)) { + } else if (mode == Addressing_Value && type != nullptr && is_type_typeid(type)) { expr->tav.value = value; - } else if (mode == Addressing_Value && is_type_proc(type)) { + } else if (mode == Addressing_Value && type != nullptr && is_type_proc(type)) { expr->tav.value = value; } diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 826c10e10..a5f688cd8 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -193,7 +193,8 @@ BuiltinProc__simd_begin, BuiltinProc_simd_gather, BuiltinProc_simd_scatter, - + BuiltinProc_simd_masked_load, + BuiltinProc_simd_masked_store, // Platform specific SIMD intrinsics BuiltinProc_simd_x86__MM_SHUFFLE, @@ -525,8 +526,10 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_lanes_rotate_left"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_lanes_rotate_right"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("simd_gather"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("simd_scatter"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_gather"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_scatter"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_masked_load"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_masked_store"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_x86__MM_SHUFFLE"), 4, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 5ccbd3399..bfdac7c96 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1691,20 +1691,24 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn case BuiltinProc_simd_gather: case BuiltinProc_simd_scatter: + case BuiltinProc_simd_masked_load: + case BuiltinProc_simd_masked_store: { LLVMValueRef ptr = arg0.value; LLVMValueRef val = arg1.value; LLVMValueRef mask = arg2.value; - unsigned count = cast(unsigned)get_array_type_count(arg0.type); + unsigned count = cast(unsigned)get_array_type_count(arg1.type); LLVMTypeRef mask_type = LLVMVectorType(LLVMInt1TypeInContext(p->module->ctx), count); mask = LLVMBuildTrunc(p->builder, mask, mask_type, ""); char const *name = nullptr; switch (builtin_id) { - case BuiltinProc_simd_gather: name = "llvm.masked.gather"; break; - case BuiltinProc_simd_scatter: name = "llvm.masked.scatter"; break; + case BuiltinProc_simd_gather: name = "llvm.masked.gather"; break; + case BuiltinProc_simd_scatter: name = "llvm.masked.scatter"; break; + case BuiltinProc_simd_masked_load: name = "llvm.masked.load"; break; + case BuiltinProc_simd_masked_store: name = "llvm.masked.store"; break; } LLVMTypeRef types[2] = { lb_type(p->module, arg1.type), @@ -1716,12 +1720,20 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn LLVMValueRef args[4] = {}; switch (builtin_id) { + case BuiltinProc_simd_masked_load: + types[1] = lb_type(p->module, t_rawptr); + /*fallthrough*/ case BuiltinProc_simd_gather: args[0] = ptr; args[1] = align; args[2] = mask; args[3] = val; + // res.type = arg1.type; break; + + case BuiltinProc_simd_masked_store: + types[1] = lb_type(p->module, t_rawptr); + /*fallthrough*/ case BuiltinProc_simd_scatter: args[0] = val; args[1] = ptr; From 80ea4e0aeb0de21fe0855c468669c16ec48b8c40 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 14:25:33 +0100 Subject: [PATCH 102/122] Remove dead code --- base/intrinsics/intrinsics.odin | 3 --- src/llvm_backend_proc.cpp | 1 - 2 files changed, 4 deletions(-) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 7aa56a9e9..e78a41719 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -240,9 +240,6 @@ simd_shr :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T --- simd_shl_masked :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T --- simd_shr_masked :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T --- -simd_add_sat :: proc(a, b: #simd[N]T) -> #simd[N]T --- -simd_sub_sat :: proc(a, b: #simd[N]T) -> #simd[N]T --- - simd_bit_and :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_bit_or :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_bit_xor :: proc(a, b: #simd[N]T) -> #simd[N]T --- diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index bfdac7c96..ce1cc8586 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1728,7 +1728,6 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn args[1] = align; args[2] = mask; args[3] = val; - // res.type = arg1.type; break; case BuiltinProc_simd_masked_store: From 78919f85249a6136929be772319694cf6c1e4df1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 14:48:55 +0100 Subject: [PATCH 103/122] Fix typos --- core/simd/simd.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/simd/simd.odin b/core/simd/simd.odin index f8924e5de..e93c94687 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -106,8 +106,8 @@ lanes_ge :: intrinsics.simd_lanes_ge // Gather and Scatter intrinsics gather :: intrinsics.simd_gather scatter :: intrinsics.simd_scatter -masked_load :: intrinsics.simd_gather -masked_store :: intrinsics.simd_scatter +masked_load :: intrinsics.simd_masked_load +masked_store :: intrinsics.simd_masked_store // extract :: proc(a: #simd[N]T, idx: uint) -> T From f56abf37804240c508f0ca7f249176208d333c72 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 14:54:09 +0100 Subject: [PATCH 104/122] Add `intrinsics.masked_expand_load` and `intrinsics.masked_compress_store` --- base/intrinsics/intrinsics.odin | 4 ++++ core/simd/simd.odin | 3 ++- src/check_builtin.cpp | 7 ++++++- src/checker_builtin_procs.hpp | 4 ++++ src/llvm_backend_proc.cpp | 32 +++++++++++++++++++++++++++----- 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index e78a41719..c78559f3f 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -286,6 +286,10 @@ simd_scatter :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) simd_masked_load :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- simd_masked_store :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- +simd_masked_expand_load :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- +simd_masked_compress_store :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- + + simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T --- simd_select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index e93c94687..1f3c67b72 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -108,7 +108,8 @@ gather :: intrinsics.simd_gather scatter :: intrinsics.simd_scatter masked_load :: intrinsics.simd_masked_load masked_store :: intrinsics.simd_masked_store - +masked_expand_load :: intrinsics.simd_masked_expand_load +masked_compress_store :: intrinsics.simd_masked_compress_store // extract :: proc(a: #simd[N]T, idx: uint) -> T extract :: intrinsics.simd_extract diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b5851bc01..bde102a8d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -667,12 +667,16 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan case BuiltinProc_simd_scatter: case BuiltinProc_simd_masked_load: case BuiltinProc_simd_masked_store: + case BuiltinProc_simd_masked_expand_load: + case BuiltinProc_simd_masked_compress_store: { // gather (ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T // scatter(ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) // masked_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T // masked_store(ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) + // masked_expand_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T + // masked_compress_store(ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) Operand ptr = {}; Operand values = {}; @@ -733,7 +737,8 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan } if (id == BuiltinProc_simd_gather || - id == BuiltinProc_simd_masked_load) { + id == BuiltinProc_simd_masked_load || + id == BuiltinProc_simd_masked_expand_load) { operand->mode = Addressing_Value; operand->type = values.type; } else { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index a5f688cd8..6245dadaf 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -195,6 +195,8 @@ BuiltinProc__simd_begin, BuiltinProc_simd_scatter, BuiltinProc_simd_masked_load, BuiltinProc_simd_masked_store, + BuiltinProc_simd_masked_expand_load, + BuiltinProc_simd_masked_compress_store, // Platform specific SIMD intrinsics BuiltinProc_simd_x86__MM_SHUFFLE, @@ -530,6 +532,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_scatter"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_masked_load"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_masked_store"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_masked_expand_load"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_masked_compress_store"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_x86__MM_SHUFFLE"), 4, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ce1cc8586..ceaeb1aca 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1693,6 +1693,8 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn case BuiltinProc_simd_scatter: case BuiltinProc_simd_masked_load: case BuiltinProc_simd_masked_store: + case BuiltinProc_simd_masked_expand_load: + case BuiltinProc_simd_masked_compress_store: { LLVMValueRef ptr = arg0.value; LLVMValueRef val = arg1.value; @@ -1705,11 +1707,14 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn char const *name = nullptr; switch (builtin_id) { - case BuiltinProc_simd_gather: name = "llvm.masked.gather"; break; - case BuiltinProc_simd_scatter: name = "llvm.masked.scatter"; break; - case BuiltinProc_simd_masked_load: name = "llvm.masked.load"; break; - case BuiltinProc_simd_masked_store: name = "llvm.masked.store"; break; + case BuiltinProc_simd_gather: name = "llvm.masked.gather"; break; + case BuiltinProc_simd_scatter: name = "llvm.masked.scatter"; break; + case BuiltinProc_simd_masked_load: name = "llvm.masked.load"; break; + case BuiltinProc_simd_masked_store: name = "llvm.masked.store"; break; + case BuiltinProc_simd_masked_expand_load: name = "llvm.masked.expandload"; break; + case BuiltinProc_simd_masked_compress_store: name = "llvm.masked.compressstore"; break; } + unsigned type_count = 2; LLVMTypeRef types[2] = { lb_type(p->module, arg1.type), lb_type(p->module, arg0.type) @@ -1718,6 +1723,7 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn auto alignment = cast(unsigned long long)type_align_of(base_array_type(arg1.type)); LLVMValueRef align = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), alignment, false); + unsigned arg_count = 4; LLVMValueRef args[4] = {}; switch (builtin_id) { case BuiltinProc_simd_masked_load: @@ -1739,9 +1745,25 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn args[2] = align; args[3] = mask; break; + + case BuiltinProc_simd_masked_expand_load: + arg_count = 3; + type_count = 1; + args[0] = ptr; + args[1] = mask; + args[2] = val; + break; + + case BuiltinProc_simd_masked_compress_store: + arg_count = 3; + type_count = 1; + args[0] = val; + args[1] = ptr; + args[2] = mask; + break; } - res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + res.value = lb_call_intrinsic(p, name, args, arg_count, types, type_count); return res; } From 2d32b819dc30355b199f66aa59c9db5b98615cf8 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Mon, 5 Aug 2024 16:32:34 +0200 Subject: [PATCH 105/122] common.odin compile fix Fix for "Error: Prefer to separate 'where' clauses with a comma rather than '&&'" --- core/image/common.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/image/common.odin b/core/image/common.odin index 6ae9850da..c9558bb0d 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -590,7 +590,7 @@ Channel :: enum u8 { // Take a slice of pixels (`[]RGBA_Pixel`, etc), and return an `Image` // Don't call `destroy` on the resulting `Image`. Instead, delete the original `pixels` slice. -pixels_to_image :: proc(pixels: [][$N]$E, width: int, height: int) -> (img: Image, ok: bool) where E == u8 || E == u16, N >= 1 && N <= 4 { +pixels_to_image :: proc(pixels: [][$N]$E, width: int, height: int) -> (img: Image, ok: bool) where E == u8 || E == u16, N >= 1, N <= 4 { if len(pixels) != width * height { return {}, false } From 6175efde3d4b2ec2cdac172cce0f2d1887705af2 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 5 Aug 2024 17:23:50 +0200 Subject: [PATCH 106/122] Fix crash if referencing import "aliased" in other file. Fixes #4026 --- src/check_expr.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b291cbe70..4bce42129 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5158,6 +5158,14 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod Scope *import_scope = e->ImportName.scope; String entity_name = selector->Ident.token.string; + if (import_scope == nullptr) { + ERROR_BLOCK(); + error(node, "'%.*s' is not imported in this file, '%.*s' is unavailable", LIT(import_name), LIT(entity_name)); + operand->mode = Addressing_Invalid; + operand->expr = node; + return nullptr; + } + check_op_expr = false; entity = scope_lookup_current(import_scope, entity_name); bool allow_builtin = false; From b63657d293caaa68e6972b8dbb3a3b3e85524e85 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Mon, 5 Aug 2024 17:23:58 +0200 Subject: [PATCH 107/122] Fix for blend_pixel.odin in core/image/common.odin not compiling --- core/image/common.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/image/common.odin b/core/image/common.odin index c9558bb0d..62deb60a9 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -1293,7 +1293,7 @@ blend_single_channel :: #force_inline proc(fg, alpha, bg: $T) -> (res: T) where return T(c & (MAX - 1)) } -blend_pixel :: #force_inline proc(fg: [$N]$T, alpha: T, bg: [N]T) -> (res: [N]T) where (T == u8 || T == u16), N >= 1 && N <= 4 { +blend_pixel :: #force_inline proc(fg: [$N]$T, alpha: T, bg: [N]T) -> (res: [N]T) where (T == u8 || T == u16), N >= 1, N <= 4 { MAX :: 256 when T == u8 else 65536 when N == 1 { From eba0774bf3bd2b89ca64f6851d465cb74559005c Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:23:09 -0400 Subject: [PATCH 108/122] Prevent `SIGPIPE` on Darwin when writing to a closed `core:net` socket Mimics behavior found on Linux implementation. --- core/net/socket_darwin.odin | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/net/socket_darwin.odin b/core/net/socket_darwin.odin index 10069963a..83280cad9 100644 --- a/core/net/socket_darwin.odin +++ b/core/net/socket_darwin.odin @@ -35,6 +35,10 @@ Socket_Option :: enum c.int { Send_Timeout = c.int(os.SO_SNDTIMEO), } +// https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/socket.h#L1025-L1027 +// Prevent the raising of SIGPIPE on writing to a closed network socket. +@private MSG_NOSIGNAL :: 0x80000 + @(private) _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) { c_type, c_protocol, c_family: int @@ -194,7 +198,7 @@ _send_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Net for bytes_written < len(buf) { limit := min(int(max(i32)), len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] - res, res_err := os.send(os.Socket(skt), remaining, 0) + res, res_err := os.send(os.Socket(skt), remaining, MSG_NOSIGNAL) if res_err != nil { err = TCP_Send_Error(os.is_platform_error(res_err) or_else -1) return @@ -210,7 +214,7 @@ _send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: for bytes_written < len(buf) { limit := min(1<<31, len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] - res, res_err := os.sendto(os.Socket(skt), remaining, 0, cast(^os.SOCKADDR)&toaddr, i32(toaddr.len)) + res, res_err := os.sendto(os.Socket(skt), remaining, MSG_NOSIGNAL, cast(^os.SOCKADDR)&toaddr, i32(toaddr.len)) if res_err != nil { err = UDP_Send_Error(os.is_platform_error(res_err) or_else -1) return From 3512d7c672883da61a6a4e128242f5f3b56a830f Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:48:45 -0400 Subject: [PATCH 109/122] Move Darwin `MSG_NOSIGNAL` to `core:os` --- core/net/socket_darwin.odin | 8 ++------ core/os/os_darwin.odin | 4 ++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/net/socket_darwin.odin b/core/net/socket_darwin.odin index 83280cad9..83c627423 100644 --- a/core/net/socket_darwin.odin +++ b/core/net/socket_darwin.odin @@ -35,10 +35,6 @@ Socket_Option :: enum c.int { Send_Timeout = c.int(os.SO_SNDTIMEO), } -// https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/socket.h#L1025-L1027 -// Prevent the raising of SIGPIPE on writing to a closed network socket. -@private MSG_NOSIGNAL :: 0x80000 - @(private) _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) { c_type, c_protocol, c_family: int @@ -198,7 +194,7 @@ _send_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Net for bytes_written < len(buf) { limit := min(int(max(i32)), len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] - res, res_err := os.send(os.Socket(skt), remaining, MSG_NOSIGNAL) + res, res_err := os.send(os.Socket(skt), remaining, os.MSG_NOSIGNAL) if res_err != nil { err = TCP_Send_Error(os.is_platform_error(res_err) or_else -1) return @@ -214,7 +210,7 @@ _send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: for bytes_written < len(buf) { limit := min(1<<31, len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] - res, res_err := os.sendto(os.Socket(skt), remaining, MSG_NOSIGNAL, cast(^os.SOCKADDR)&toaddr, i32(toaddr.len)) + res, res_err := os.sendto(os.Socket(skt), remaining, os.MSG_NOSIGNAL, cast(^os.SOCKADDR)&toaddr, i32(toaddr.len)) if res_err != nil { err = UDP_Send_Error(os.is_platform_error(res_err) or_else -1) return diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 09cdd84d0..f21dbb676 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -492,6 +492,10 @@ in6_addr :: struct #packed { s6_addr: [16]u8, } +// https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/socket.h#L1025-L1027 +// Prevent the raising of SIGPIPE on writing to a closed network socket. +MSG_NOSIGNAL :: 0x80000 + SIOCGIFFLAG :: enum c.int { UP = 0, /* Interface is up. */ BROADCAST = 1, /* Broadcast address valid. */ From 4c0ab09c9a88ae644b4b6ecd0a5b541428b0be24 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:51:56 -0400 Subject: [PATCH 110/122] Handle `EPIPE` in Darwin `core:net` --- core/net/socket_darwin.odin | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/net/socket_darwin.odin b/core/net/socket_darwin.odin index 83c627423..ba369810b 100644 --- a/core/net/socket_darwin.odin +++ b/core/net/socket_darwin.odin @@ -195,7 +195,11 @@ _send_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Net limit := min(int(max(i32)), len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] res, res_err := os.send(os.Socket(skt), remaining, os.MSG_NOSIGNAL) - if res_err != nil { + if res_err == os.EPIPE { + // EPIPE arises if the socket has been closed remotely. + err = TCP_Send_Error.Connection_Closed + return + } else if res_err != nil { err = TCP_Send_Error(os.is_platform_error(res_err) or_else -1) return } @@ -211,7 +215,11 @@ _send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: limit := min(1<<31, len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] res, res_err := os.sendto(os.Socket(skt), remaining, os.MSG_NOSIGNAL, cast(^os.SOCKADDR)&toaddr, i32(toaddr.len)) - if res_err != nil { + if res_err == os.EPIPE { + // EPIPE arises if the socket has been closed remotely. + err = UDP_Send_Error.Not_Socket + return + } else if res_err != nil { err = UDP_Send_Error(os.is_platform_error(res_err) or_else -1) return } From 4902288a5a7885d348cdf04ac33768783db08e31 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 5 Aug 2024 22:04:16 +0200 Subject: [PATCH 111/122] Add `reflect.struct_field_count` that returns the number of fields in a struct type Example: ```odin package struct_count_example import "core:fmt" import "core:reflect" import "core:dynlib" Foo :: struct{ one: int, two: f32, } Bar :: struct { three: int, four: bool, five: f64, } Game_Api :: struct { init: proc(api: ^Game_Api), update: proc(api: ^Game_Api), using foo: Foo, bar: Bar, // Private stuff reload_count: int, __handle: rawptr, } API_PRIVATE_COUNT :: 2 game_api: Game_Api main :: proc() { fmt.printfln("Game_Api, .Top: %v", reflect.struct_field_count(Game_Api)) // 6 fmt.printfln("Game_Api, .Using: %v", reflect.struct_field_count(Game_Api, .Using)) // 8 fmt.printfln("Game_Api, .Recursive: %v", reflect.struct_field_count(Game_Api, .Recursive)) // 11 symbols_loaded, _ := dynlib.initialize_symbols(&game_api, "game.dll") symbols_expected := reflect.struct_field_count(Game_Api) - API_PRIVATE_COUNT if symbols_loaded == -1 { fmt.eprintln("Couldn't load game.dll") return } else if symbols_loaded != symbols_expected { fmt.eprintfln("Expected %v symbols, got %v", symbols_expected, symbols_loaded) return } } ``` --- core/reflect/reflect.odin | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 23c0f803e..9a5551d42 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -496,6 +496,62 @@ struct_field_offsets :: proc(T: typeid) -> []uintptr { return nil } +Struct_Field_Count_Method :: enum { + Top_Level, + Using, + Recursive, +} + +/* +Counts the number of fields in a struct + +This procedure returns the number of fields in a struct, counting in one of three ways: +- .Top_Level: Only counts the top-level fields +- .Using: Same count as .Top_Level, and adds the field count of any `using s: Struct` it encounters (in addition to itself) +- .Recursive: The count of all top-level fields, plus the count of any child struct's fields, recursively + +Inputs: +- T: The struct type +- method: The counting method + +Returns: +- The `count`, enumerated using the `method`, which will be `0` if the type is not a struct + +Example: + expected_count := reflect.struct_field_count(Game_API) - API_PRIVATE_COUNT + if symbols_loaded != expected_count { + fmt.eprintf("Expected %v symbols, got %v", expected_count, symbols_loaded) + return + } +*/ +@(require_results) +struct_field_count :: proc(T: typeid, method := Struct_Field_Count_Method.Top_Level) -> (count: int) { + ti := runtime.type_info_base(type_info_of(T)) + if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { + switch method { + case .Top_Level: + return int(s.field_count) + + case .Using: + count = int(s.field_count) + for type, i in s.types[:s.field_count] { + if s.usings[i] { + count += struct_field_count(type.id) + } + } + + case .Recursive: + count = int(s.field_count) + for type in s.types[:s.field_count] { + count += struct_field_count(type.id) + } + + case: return 0 + } + } + return +} + @(require_results) struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) { ti := runtime.type_info_base(type_info_of(T)) From 17ebaffce8f97b895c651bf57567b13f2685f849 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 5 Aug 2024 22:12:22 +0200 Subject: [PATCH 112/122] Update comment. --- core/reflect/reflect.odin | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 9a5551d42..aff82136a 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -518,9 +518,11 @@ Returns: - The `count`, enumerated using the `method`, which will be `0` if the type is not a struct Example: - expected_count := reflect.struct_field_count(Game_API) - API_PRIVATE_COUNT - if symbols_loaded != expected_count { - fmt.eprintf("Expected %v symbols, got %v", expected_count, symbols_loaded) + symbols_loaded, ok := dynlib.initialize_symbols(&game_api, "game.dll") + symbols_expected := reflect.struct_field_count(Game_Api) - API_PRIVATE_COUNT + + if symbols_loaded != symbols_expected { + fmt.eprintf("Expected %v symbols, got %v", symbols_expected, symbols_loaded) return } */ From bed18a17e6fbad407ac0304e5ca0b3058e1d9276 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 6 Aug 2024 11:22:34 +0100 Subject: [PATCH 113/122] Bodge: Improve `aligned_resize` logic --- base/runtime/heap_allocator.odin | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/base/runtime/heap_allocator.odin b/base/runtime/heap_allocator.odin index cdad8690e..a0a984f10 100644 --- a/base/runtime/heap_allocator.odin +++ b/base/runtime/heap_allocator.odin @@ -19,12 +19,15 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, // the pointer we return to the user. // - aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil, zero_memory := true) -> ([]byte, Allocator_Error) { + aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr, old_size: int, zero_memory := true) -> ([]byte, Allocator_Error) { a := max(alignment, align_of(rawptr)) space := size + a - 1 allocated_mem: rawptr - if old_ptr != nil { + + force_copy := old_ptr != nil && a > align_of(rawptr) + + if !force_copy && old_ptr != nil { original_old_ptr := ([^]rawptr)(old_ptr)[-1] allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr)) } else { @@ -36,12 +39,19 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) diff := int(aligned_ptr - ptr) if (size + diff) > space || allocated_mem == nil { + aligned_free(old_ptr) + aligned_free(allocated_mem) return nil, .Out_Of_Memory } aligned_mem = rawptr(aligned_ptr) ([^]rawptr)(aligned_mem)[-1] = allocated_mem + if force_copy { + mem_copy_non_overlapping(aligned_mem, old_ptr, old_size) + aligned_free(old_ptr) + } + return byte_slice(aligned_mem, size), nil } @@ -53,10 +63,10 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int, zero_memory := true) -> (new_memory: []byte, err: Allocator_Error) { if p == nil { - return nil, nil + return aligned_alloc(new_size, new_alignment, nil, old_size, zero_memory) } - new_memory = aligned_alloc(new_size, new_alignment, p, zero_memory) or_return + new_memory = aligned_alloc(new_size, new_alignment, p, old_size, zero_memory) or_return // NOTE: heap_resize does not zero the new memory, so we do it if zero_memory && new_size > old_size { @@ -68,7 +78,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, switch mode { case .Alloc, .Alloc_Non_Zeroed: - return aligned_alloc(size, alignment, nil, mode == .Alloc) + return aligned_alloc(size, alignment, nil, 0, mode == .Alloc) case .Free: aligned_free(old_memory) @@ -77,9 +87,6 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, return nil, .Mode_Not_Implemented case .Resize, .Resize_Non_Zeroed: - if old_memory == nil { - return aligned_alloc(size, alignment, nil, mode == .Resize) - } return aligned_resize(old_memory, old_size, size, alignment, mode == .Resize) case .Query_Features: From 6a6f0781867907d9d62b321f25d3b889b7559161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rikard=20Petr=C3=A9?= Date: Tue, 6 Aug 2024 19:48:38 +0200 Subject: [PATCH 114/122] Fix missing closing brace for Bit_Field in core:odin/parser --- core/odin/parser/parser.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 24c85a19e..7c0fe2e98 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2845,7 +2845,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { close := expect_closing_brace_of_field_list(p) - bf := ast.new(ast.Bit_Field_Type, tok.pos, close.pos) + bf := ast.new(ast.Bit_Field_Type, tok.pos, end_pos(close)) bf.tok_pos = tok.pos bf.backing_type = backing_type From 7a367c9c08639ded09b342714e02bdbc82ecb604 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:49:56 -0400 Subject: [PATCH 115/122] Fix documented names of a few SIMD procedures --- base/intrinsics/intrinsics.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index c78559f3f..c70c63bb3 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -303,11 +303,11 @@ simd_nearest :: proc(a: #simd[N]any_float) -> #simd[N]any_float --- simd_to_bits :: proc(v: #simd[N]T) -> #simd[N]Integer where size_of(T) == size_of(Integer), type_is_unsigned(Integer) --- -// equivalent a swizzle with descending indices, e.g. reserve(a, 3, 2, 1, 0) -simd_reverse :: proc(a: #simd[N]T) -> #simd[N]T --- +// equivalent to a swizzle with descending indices, e.g. reserve(a, 3, 2, 1, 0) +simd_lanes_reverse :: proc(a: #simd[N]T) -> #simd[N]T --- -simd_rotate_left :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T --- -simd_rotate_right :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T --- +simd_lanes_rotate_left :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T --- +simd_lanes_rotate_right :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T --- // Checks if the current target supports the given target features. // From e27a424f4d88a0409e6492ab167dbe5a82b9e3ac Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:50:34 -0400 Subject: [PATCH 116/122] Swap `reduce_any` and `reduce_all` `llvm.vector.reduce.or` will return true if any lane is true. `llvm.vector.reduce.and` will return true if all lanes are true. --- src/llvm_backend_proc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ceaeb1aca..ee3ed1995 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1532,8 +1532,8 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn { char const *name = nullptr; switch (builtin_id) { - case BuiltinProc_simd_reduce_any: name = "llvm.vector.reduce.and"; break; - case BuiltinProc_simd_reduce_all: name = "llvm.vector.reduce.or"; break; + case BuiltinProc_simd_reduce_any: name = "llvm.vector.reduce.or"; break; + case BuiltinProc_simd_reduce_all: name = "llvm.vector.reduce.and"; break; } LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) }; From e5a478d393472ba2d9d5b8eac0a73be847df02f6 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 6 Aug 2024 21:41:31 +0200 Subject: [PATCH 117/122] wgpu: fix examples after changing color to an array --- vendor/wgpu/examples/glfw/main.odin | 2 +- vendor/wgpu/examples/sdl2/main.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/wgpu/examples/glfw/main.odin b/vendor/wgpu/examples/glfw/main.odin index 39161311c..bddd2c5f7 100644 --- a/vendor/wgpu/examples/glfw/main.odin +++ b/vendor/wgpu/examples/glfw/main.odin @@ -158,7 +158,7 @@ frame :: proc "c" (dt: f32) { view = frame, loadOp = .Clear, storeOp = .Store, - clearValue = { r = 0, g = 1, b = 0, a = 1 }, + clearValue = { 0, 1, 0, 1 }, }, }, ) diff --git a/vendor/wgpu/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin index 3d79346d0..fa0a84bd5 100644 --- a/vendor/wgpu/examples/sdl2/main.odin +++ b/vendor/wgpu/examples/sdl2/main.odin @@ -158,7 +158,7 @@ frame :: proc "c" (dt: f32) { view = frame, loadOp = .Clear, storeOp = .Store, - clearValue = { r = 0, g = 1, b = 0, a = 1 }, + clearValue = { 0, 1, 0, 1 }, }, }, ) From 6fe938b946dc2be977c8b94f754b84bb8c42f440 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 6 Aug 2024 21:41:54 +0200 Subject: [PATCH 118/122] darwin: add setAllowedFileTypes binding for open panels --- core/sys/darwin/Foundation/NSOpenPanel.odin | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/sys/darwin/Foundation/NSOpenPanel.odin b/core/sys/darwin/Foundation/NSOpenPanel.odin index ac5f9674e..482347daa 100644 --- a/core/sys/darwin/Foundation/NSOpenPanel.odin +++ b/core/sys/darwin/Foundation/NSOpenPanel.odin @@ -29,3 +29,7 @@ OpenPanel_setResolvesAliases :: proc "c" (self: ^OpenPanel, setting: BOOL) { OpenPanel_setAllowsMultipleSelection :: proc "c" (self: ^OpenPanel, setting: BOOL) { msgSend(nil, self, "setAllowsMultipleSelection:", setting) } +@(objc_type=OpenPanel, objc_name="setAllowedFileTypes") +OpenPanel_setAllowedFileTypes :: proc "c" (self: ^OpenPanel, types: ^Array) { + msgSend(nil, self, "setAllowedFileTypes:", types) +} From 69a15ca5b61e531e3f873ae84335e7d253217f15 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 7 Aug 2024 14:50:45 +0200 Subject: [PATCH 119/122] Don't copy LLVM shared object on Linux We copy the LLVM shared object when building Odin on Linux. Contrary the comment in `build_odin.sh`, this is unnecessary, and Odin can be compiled and itself compile things just fine without this step. This is then packaged up at release and leads to #4019 and #4033. The Linux release builds are built on Ubuntu and not strictly supported on other Linux distributions. Building from source is preferred. --- build_odin.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_odin.sh b/build_odin.sh index 125b9335a..066f48c20 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -95,7 +95,7 @@ Linux) LDFLAGS="$LDFLAGS -ldl $($LLVM_CONFIG --libs core native --system-libs --libfiles)" # Copy libLLVM*.so into current directory for linking # NOTE: This is needed by the Linux release pipeline! - cp $(readlink -f $($LLVM_CONFIG --libfiles)) ./ + # cp $(readlink -f $($LLVM_CONFIG --libfiles)) ./ LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN" ;; OpenBSD) From c9b69d76b01078fbd6f546925cb5c18daf3cd49a Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 7 Aug 2024 17:21:56 +0200 Subject: [PATCH 120/122] text/edit: fix undo_state_push wrong builder check --- core/text/edit/text_edit.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/text/edit/text_edit.odin b/core/text/edit/text_edit.odin index a4f8c06b9..521a658e1 100644 --- a/core/text/edit/text_edit.odin +++ b/core/text/edit/text_edit.odin @@ -137,7 +137,7 @@ clear_all :: proc(s: ^State) -> (cleared: bool) { // push current text state to the wanted undo|redo stack undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) -> mem.Allocator_Error { - if s.builder != nil { + if s.builder == nil { return nil } text := string(s.builder.buf[:]) From 2bf055ec6e0f19cd7f75c51ab9af33519b2b7f3c Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 7 Aug 2024 19:38:36 +0200 Subject: [PATCH 121/122] Delete empty file after access check. --- src/build_settings.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 3e2d11101..f7ff0ea09 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -2020,9 +2020,11 @@ gb_internal bool init_build_paths(String init_filename) { return false; } - gbFile output_file_test; - gbFileError output_test_err = gb_file_open_mode(&output_file_test, gbFileMode_Append | gbFileMode_Rw, (const char*)output_file.text); - defer (gb_file_close(&output_file_test)); + gbFile output_file_test; + const char* output_file_name = (const char*)output_file.text; + gbFileError output_test_err = gb_file_open_mode(&output_file_test, gbFileMode_Append | gbFileMode_Rw, output_file_name); + gb_file_close(&output_file_test); + gb_file_remove(output_file_name); if (output_test_err != 0) { String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); From 796feeead9ef2625351ec6745ce7cbc5dde8a911 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 7 Aug 2024 22:12:23 +0200 Subject: [PATCH 122/122] Remove LLVM copy from nightly. --- .github/workflows/nightly.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index e4bc5d81c..0c5526d0f 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -61,7 +61,6 @@ jobs: mkdir dist cp odin dist cp LICENSE dist - cp libLLVM* dist cp -r shared dist cp -r base dist cp -r core dist