Remove unneeded semicolons from the core library

This commit is contained in:
gingerBill
2021-08-31 22:21:13 +01:00
parent b176af2742
commit 251da264ed
187 changed files with 27227 additions and 27227 deletions
+48 -48
View File
@@ -8,100 +8,100 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
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 {
return;
return
}
if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 {
return;
return
}
path := strings.concatenate({base_path, `\`, win32.utf16_to_utf8(d.cFileName[:])});
fi.fullpath = path;
fi.name = basename(path);
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow);
path := strings.concatenate({base_path, `\`, win32.utf16_to_utf8(d.cFileName[:])})
fi.fullpath = path
fi.name = basename(path)
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
if d.dwFileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
fi.mode |= 0o444;
fi.mode |= 0o444
} else {
fi.mode |= 0o666;
fi.mode |= 0o666
}
is_sym := false;
is_sym := false
if d.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_Point == 0 {
is_sym = false;
is_sym = false
} else {
is_sym = d.dwReserved0 == win32.IO_REPARSE_TAG_SYMLINK || d.dwReserved0 == win32.IO_REPARSE_TAG_MOUNT_POINT;
is_sym = d.dwReserved0 == win32.IO_REPARSE_TAG_SYMLINK || d.dwReserved0 == win32.IO_REPARSE_TAG_MOUNT_POINT
}
if is_sym {
fi.mode |= File_Mode_Sym_Link;
fi.mode |= File_Mode_Sym_Link
} else {
if d.dwFileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
fi.mode |= 0o111 | File_Mode_Dir;
fi.mode |= 0o111 | File_Mode_Dir
}
// fi.mode |= file_type_mode(h);
}
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));
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))
fi.is_dir = fi.mode & File_Mode_Dir != 0;
return;
fi.is_dir = fi.mode & File_Mode_Dir != 0
return
}
if fd == 0 {
return nil, ERROR_INVALID_HANDLE;
return nil, ERROR_INVALID_HANDLE
}
context.allocator = allocator;
context.allocator = allocator
h := win32.HANDLE(fd);
h := win32.HANDLE(fd)
dir_fi, _ := file_info_from_get_file_information_by_handle("", h);
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, ERROR_FILE_IS_NOT_DIR
}
n := n;
size := n;
n := n
size := n
if n <= 0 {
n = -1;
size = 100;
n = -1
size = 100
}
dfi := make([dynamic]File_Info, 0, size);
dfi := make([dynamic]File_Info, 0, size)
wpath: []u16;
wpath, err = cleanpath_from_handle_u16(fd);
wpath: []u16
wpath, err = cleanpath_from_handle_u16(fd)
if len(wpath) == 0 || err != ERROR_NONE {
return;
return
}
wpath_search := make([]u16, len(wpath)+3, context.temp_allocator);
copy(wpath_search, wpath);
wpath_search[len(wpath)+0] = '\\';
wpath_search[len(wpath)+1] = '*';
wpath_search[len(wpath)+2] = 0;
wpath_search := make([]u16, len(wpath)+3, context.temp_allocator)
copy(wpath_search, wpath)
wpath_search[len(wpath)+0] = '\\'
wpath_search[len(wpath)+1] = '*'
wpath_search[len(wpath)+2] = 0
path := cleanpath_from_buf(wpath);
path := cleanpath_from_buf(wpath)
find_data := &win32.WIN32_FIND_DATAW{};
find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data);
defer win32.FindClose(find_handle);
find_data := &win32.WIN32_FIND_DATAW{}
find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data)
defer win32.FindClose(find_handle)
for n != 0 && find_handle != nil {
fi: File_Info;
fi = find_data_to_file_info(path, find_data);
fi: File_Info
fi = find_data_to_file_info(path, find_data)
if fi.name != "" {
append(&dfi, fi);
n -= 1;
append(&dfi, fi)
n -= 1
}
if !win32.FindNextFileW(find_handle, find_data) {
e := Errno(win32.GetLastError());
e := Errno(win32.GetLastError())
if e == ERROR_NO_MORE_FILES {
break;
break
}
return dfi[:], e;
return dfi[:], e
}
}
return dfi[:], ERROR_NONE;
return dfi[:], ERROR_NONE
}
+30 -30
View File
@@ -8,26 +8,26 @@ import win32 "core:sys/windows"
// NOTE: the value will be allocated with the supplied allocator
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
if key == "" {
return;
return
}
wkey := win32.utf8_to_wstring(key);
b := make([dynamic]u16, 100, context.temp_allocator);
wkey := win32.utf8_to_wstring(key)
b := make([dynamic]u16, 100, context.temp_allocator)
for {
n := win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)));
n := win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
if n == 0 {
err := win32.GetLastError();
err := win32.GetLastError()
if err == u32(ERROR_ENVVAR_NOT_FOUND) {
return "", false;
return "", false
}
}
if n <= u32(len(b)) {
value = win32.utf16_to_utf8(b[:n], allocator);
found = true;
return;
value = win32.utf16_to_utf8(b[:n], allocator)
found = true
return
}
resize(&b, len(b)*2);
resize(&b, len(b)*2)
}
}
@@ -37,62 +37,62 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
// To distinguish between an empty value and an unset value, use lookup_env
// NOTE: the value will be allocated with the supplied allocator
get_env :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator);
return;
value, _ = lookup_env(key, allocator)
return
}
// set_env sets the value of the environment variable named by the key
set_env :: proc(key, value: string) -> Errno {
k := win32.utf8_to_wstring(key);
v := win32.utf8_to_wstring(value);
k := win32.utf8_to_wstring(key)
v := win32.utf8_to_wstring(value)
if !win32.SetEnvironmentVariableW(k, v) {
return Errno(win32.GetLastError());
return Errno(win32.GetLastError())
}
return 0;
return 0
}
// unset_env unsets a single environment variable
unset_env :: proc(key: string) -> Errno {
k := win32.utf8_to_wstring(key);
k := win32.utf8_to_wstring(key)
if !win32.SetEnvironmentVariableW(k, nil) {
return Errno(win32.GetLastError());
return Errno(win32.GetLastError())
}
return 0;
return 0
}
// 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 := cast([^]win32.WCHAR)(win32.GetEnvironmentStringsW())
if envs == nil {
return nil;
return nil
}
defer win32.FreeEnvironmentStringsW(envs);
defer win32.FreeEnvironmentStringsW(envs)
r := make([dynamic]string, 0, 50, allocator);
r := make([dynamic]string, 0, 50, allocator)
for from, i := 0, 0; true; i += 1 {
if c := envs[i]; c == 0 {
if i <= from {
break;
break
}
append(&r, win32.utf16_to_utf8(envs[from:i], allocator));
from = i + 1;
append(&r, win32.utf16_to_utf8(envs[from:i], allocator))
from = i + 1
}
}
return r[:];
return r[:]
}
// clear_env deletes all environment variables
clear_env :: proc() {
envs := environ(context.temp_allocator);
envs := environ(context.temp_allocator)
for env in envs {
for j in 1..<len(env) {
if env[j] == '=' {
unset_env(env[0:j]);
break;
unset_env(env[0:j])
break
}
}
}
+207 -207
View File
@@ -4,337 +4,337 @@ import win32 "core:sys/windows"
import "core:intrinsics"
is_path_separator :: proc(c: byte) -> bool {
return c == '/' || c == '\\';
return c == '/' || c == '\\'
}
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, ERROR_FILE_NOT_FOUND
}
access: u32;
access: u32
switch mode & (O_RDONLY|O_WRONLY|O_RDWR) {
case O_RDONLY: access = win32.FILE_GENERIC_READ;
case O_WRONLY: access = win32.FILE_GENERIC_WRITE;
case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE;
case O_RDONLY: access = win32.FILE_GENERIC_READ
case O_WRONLY: access = win32.FILE_GENERIC_WRITE
case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE
}
if mode&O_APPEND != 0 {
access &~= win32.FILE_GENERIC_WRITE;
access |= win32.FILE_APPEND_DATA;
access &~= win32.FILE_GENERIC_WRITE
access |= win32.FILE_APPEND_DATA
}
if mode&O_CREATE != 0 {
access |= win32.FILE_GENERIC_WRITE;
access |= win32.FILE_GENERIC_WRITE
}
share_mode := win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE;
sa: ^win32.SECURITY_ATTRIBUTES = nil;
sa_inherit := win32.SECURITY_ATTRIBUTES{nLength = size_of(win32.SECURITY_ATTRIBUTES), bInheritHandle = true};
share_mode := win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE
sa: ^win32.SECURITY_ATTRIBUTES = nil
sa_inherit := win32.SECURITY_ATTRIBUTES{nLength = size_of(win32.SECURITY_ATTRIBUTES), bInheritHandle = true}
if mode&O_CLOEXEC == 0 {
sa = &sa_inherit;
sa = &sa_inherit
}
create_mode: u32;
create_mode: u32
switch {
case mode&(O_CREATE|O_EXCL) == (O_CREATE | O_EXCL):
create_mode = win32.CREATE_NEW;
create_mode = win32.CREATE_NEW
case mode&(O_CREATE|O_TRUNC) == (O_CREATE | O_TRUNC):
create_mode = win32.CREATE_ALWAYS;
create_mode = win32.CREATE_ALWAYS
case mode&O_CREATE == O_CREATE:
create_mode = win32.OPEN_ALWAYS;
create_mode = win32.OPEN_ALWAYS
case mode&O_TRUNC == O_TRUNC:
create_mode = win32.TRUNCATE_EXISTING;
create_mode = win32.TRUNCATE_EXISTING
case:
create_mode = win32.OPEN_EXISTING;
create_mode = win32.OPEN_EXISTING
}
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));
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, ERROR_NONE
}
err := Errno(win32.GetLastError());
return INVALID_HANDLE, err;
err := Errno(win32.GetLastError())
return INVALID_HANDLE, err
}
close :: proc(fd: Handle) -> Errno {
if !win32.CloseHandle(win32.HANDLE(fd)) {
return Errno(win32.GetLastError());
return Errno(win32.GetLastError())
}
return ERROR_NONE;
return ERROR_NONE
}
flush :: proc(fd: Handle) -> (err: Errno) {
if !win32.FlushFileBuffers(win32.HANDLE(fd)) {
err = Errno(win32.GetLastError());
err = Errno(win32.GetLastError())
}
return;
return
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
return 0, ERROR_NONE
}
single_write_length: win32.DWORD;
total_write: i64;
length := i64(len(data));
single_write_length: win32.DWORD
total_write: i64
length := i64(len(data))
for total_write < length {
remaining := length - total_write;
to_write := win32.DWORD(min(i32(remaining), MAX_RW));
remaining := length - total_write
to_write := win32.DWORD(min(i32(remaining), MAX_RW))
e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil);
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());
return int(total_write), err;
err := Errno(win32.GetLastError())
return int(total_write), err
}
total_write += i64(single_write_length);
total_write += i64(single_write_length)
}
return int(total_write), ERROR_NONE;
return int(total_write), ERROR_NONE
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
return 0, ERROR_NONE
}
single_read_length: win32.DWORD;
total_read: i64;
length := i64(len(data));
single_read_length: win32.DWORD
total_read: i64
length := i64(len(data))
for total_read < length {
remaining := length - total_read;
to_read := min(win32.DWORD(remaining), MAX_RW);
remaining := length - total_read
to_read := min(win32.DWORD(remaining), MAX_RW)
e := win32.ReadFile(win32.HANDLE(fd), &data[total_read], to_read, &single_read_length, nil);
e := win32.ReadFile(win32.HANDLE(fd), &data[total_read], to_read, &single_read_length, nil)
if single_read_length <= 0 || !e {
err := Errno(win32.GetLastError());
return int(total_read), err;
err := Errno(win32.GetLastError())
return int(total_read), err
}
total_read += i64(single_read_length);
total_read += i64(single_read_length)
}
return int(total_read), ERROR_NONE;
return int(total_read), ERROR_NONE
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
w: u32;
w: u32
switch whence {
case 0: w = win32.FILE_BEGIN;
case 1: w = win32.FILE_CURRENT;
case 2: w = win32.FILE_END;
case 0: w = win32.FILE_BEGIN
case 1: w = win32.FILE_CURRENT
case 2: w = win32.FILE_END
}
hi := i32(offset>>32);
lo := i32(offset);
ft := win32.GetFileType(win32.HANDLE(fd));
hi := i32(offset>>32)
lo := i32(offset)
ft := win32.GetFileType(win32.HANDLE(fd))
if ft == win32.FILE_TYPE_PIPE {
return 0, ERROR_FILE_IS_PIPE;
return 0, ERROR_FILE_IS_PIPE
}
dw_ptr := win32.SetFilePointer(win32.HANDLE(fd), lo, &hi, w);
dw_ptr := win32.SetFilePointer(win32.HANDLE(fd), lo, &hi, w)
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
err := Errno(win32.GetLastError());
return 0, err;
err := Errno(win32.GetLastError())
return 0, err
}
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE
}
file_size :: proc(fd: Handle) -> (i64, Errno) {
length: win32.LARGE_INTEGER;
err: Errno;
length: win32.LARGE_INTEGER
err: Errno
if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) {
err = Errno(win32.GetLastError());
err = Errno(win32.GetLastError())
}
return i64(length), err;
return i64(length), err
}
@(private)
MAX_RW :: 1<<30;
MAX_RW :: 1<<30
@(private)
pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
buf := data;
buf := data
if len(buf) > MAX_RW {
buf = buf[:MAX_RW];
buf = buf[:MAX_RW]
}
curr_offset, e := seek(fd, offset, 1);
curr_offset, e := seek(fd, offset, 1)
if e != 0 {
return 0, e;
return 0, e
}
defer seek(fd, curr_offset, 0);
defer seek(fd, curr_offset, 0)
o := win32.OVERLAPPED{
OffsetHigh = u32(offset>>32),
Offset = u32(offset),
};
h := win32.HANDLE(fd);
done: win32.DWORD;
if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
e = Errno(win32.GetLastError());
done = 0;
}
return int(done), e;
h := win32.HANDLE(fd)
done: win32.DWORD
if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
e = Errno(win32.GetLastError())
done = 0
}
return int(done), e
}
@(private)
pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
buf := data;
buf := data
if len(buf) > MAX_RW {
buf = buf[:MAX_RW];
buf = buf[:MAX_RW]
}
curr_offset, e := seek(fd, offset, 1);
curr_offset, e := seek(fd, offset, 1)
if e != 0 {
return 0, e;
return 0, e
}
defer seek(fd, curr_offset, 0);
defer seek(fd, curr_offset, 0)
o := win32.OVERLAPPED{
OffsetHigh = u32(offset>>32),
Offset = u32(offset),
};
h := win32.HANDLE(fd);
done: win32.DWORD;
if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
e = Errno(win32.GetLastError());
done = 0;
}
return int(done), e;
h := win32.HANDLE(fd)
done: win32.DWORD
if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
e = Errno(win32.GetLastError())
done = 0
}
return int(done), e
}
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
if offset < 0 {
return 0, ERROR_NEGATIVE_OFFSET;
return 0, ERROR_NEGATIVE_OFFSET
}
b, offset := data, offset;
b, offset := data, offset
for len(b) > 0 {
m, e := pread(fd, b, offset);
m, e := pread(fd, b, offset)
if e != 0 {
err = e;
break;
err = e
break
}
n += m;
b = b[m:];
offset += i64(m);
n += m
b = b[m:]
offset += i64(m)
}
return;
return
}
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
if offset < 0 {
return 0, ERROR_NEGATIVE_OFFSET;
return 0, ERROR_NEGATIVE_OFFSET
}
b, offset := data, offset;
b, offset := data, offset
for len(b) > 0 {
m, e := pwrite(fd, b, offset);
m, e := pwrite(fd, b, offset)
if e != 0 {
err = e;
break;
err = e
break
}
n += m;
b = b[m:];
offset += i64(m);
n += m
b = b[m:]
offset += i64(m)
}
return;
return
}
// NOTE(bill): Uses startup to initialize it
stdin := get_std_handle(uint(win32.STD_INPUT_HANDLE));
stdout := get_std_handle(uint(win32.STD_OUTPUT_HANDLE));
stderr := get_std_handle(uint(win32.STD_ERROR_HANDLE));
stdin := get_std_handle(uint(win32.STD_INPUT_HANDLE))
stdout := get_std_handle(uint(win32.STD_OUTPUT_HANDLE))
stderr := get_std_handle(uint(win32.STD_ERROR_HANDLE))
get_std_handle :: proc "contextless" (h: uint) -> Handle {
fd := win32.GetStdHandle(win32.DWORD(h));
fd := win32.GetStdHandle(win32.DWORD(h))
when size_of(uintptr) == 8 {
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0)
}
return Handle(fd);
return Handle(fd)
}
exists :: proc(path: string) -> bool {
wpath := win32.utf8_to_wstring(path, context.temp_allocator);
attribs := win32.GetFileAttributesW(wpath);
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
attribs := win32.GetFileAttributesW(wpath)
return i32(attribs) != win32.INVALID_FILE_ATTRIBUTES;
return i32(attribs) != win32.INVALID_FILE_ATTRIBUTES
}
is_file :: proc(path: string) -> bool {
wpath := win32.utf8_to_wstring(path, context.temp_allocator);
attribs := win32.GetFileAttributesW(wpath);
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
attribs := win32.GetFileAttributesW(wpath)
if i32(attribs) != win32.INVALID_FILE_ATTRIBUTES {
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY == 0;
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY == 0
}
return false;
return false
}
is_dir :: proc(path: string) -> bool {
wpath := win32.utf8_to_wstring(path, context.temp_allocator);
attribs := win32.GetFileAttributesW(wpath);
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
attribs := win32.GetFileAttributesW(wpath)
if i32(attribs) != win32.INVALID_FILE_ATTRIBUTES {
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY != 0;
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY != 0
}
return false;
return false
}
// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName
@private cwd_lock := win32.SRWLOCK{}; // zero is initialized
@private cwd_lock := win32.SRWLOCK{} // zero is initialized
get_current_directory :: proc(allocator := context.allocator) -> string {
win32.AcquireSRWLockExclusive(&cwd_lock);
win32.AcquireSRWLockExclusive(&cwd_lock)
sz_utf16 := win32.GetCurrentDirectoryW(0, nil);
dir_buf_wstr := make([]u16, sz_utf16, context.temp_allocator); // the first time, it _includes_ the NUL.
sz_utf16 := win32.GetCurrentDirectoryW(0, nil)
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.
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.
win32.ReleaseSRWLockExclusive(&cwd_lock);
win32.ReleaseSRWLockExclusive(&cwd_lock)
return win32.utf16_to_utf8(dir_buf_wstr, allocator);
return win32.utf16_to_utf8(dir_buf_wstr, allocator)
}
set_current_directory :: proc(path: string) -> (err: Errno) {
wstr := win32.utf8_to_wstring(path);
wstr := win32.utf8_to_wstring(path)
win32.AcquireSRWLockExclusive(&cwd_lock);
win32.AcquireSRWLockExclusive(&cwd_lock)
if !win32.SetCurrentDirectoryW(wstr) {
err = Errno(win32.GetLastError());
err = Errno(win32.GetLastError())
}
win32.ReleaseSRWLockExclusive(&cwd_lock);
win32.ReleaseSRWLockExclusive(&cwd_lock)
return;
return
}
change_directory :: proc(path: string) -> Errno {
wpath := win32.utf8_to_wstring(path, context.temp_allocator);
return Errno(win32.SetCurrentDirectoryW(wpath));
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
return Errno(win32.SetCurrentDirectoryW(wpath))
}
make_directory :: proc(path: string, mode: u32) -> Errno {
wpath := win32.utf8_to_wstring(path, context.temp_allocator);
return Errno(win32.CreateDirectoryW(wpath, nil));
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
return Errno(win32.CreateDirectoryW(wpath, nil))
}
remove_directory :: proc(path: string) -> Errno {
wpath := win32.utf8_to_wstring(path, context.temp_allocator);
return Errno(win32.RemoveDirectoryW(wpath));
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
return Errno(win32.RemoveDirectoryW(wpath))
}
@@ -342,158 +342,158 @@ remove_directory :: proc(path: string) -> Errno {
@(private)
is_abs :: proc(path: string) -> bool {
if len(path) > 0 && path[0] == '/' {
return true;
return true
}
when ODIN_OS == "windows" {
if len(path) > 2 {
switch path[0] {
case 'A'..='Z', 'a'..='z':
return path[1] == ':' && is_path_separator(path[2]);
return path[1] == ':' && is_path_separator(path[2])
}
}
}
return false;
return false
}
@(private)
fix_long_path :: proc(path: string) -> string {
if len(path) < 248 {
return path;
return path
}
if len(path) >= 2 && path[:2] == `\\` {
return path;
return path
}
if !is_abs(path) {
return path;
return path
}
prefix :: `\\?`;
prefix :: `\\?`
path_buf := make([]byte, len(prefix)+len(path)+len(`\`), context.temp_allocator);
copy(path_buf, prefix);
n := len(path);
r, w := 0, len(prefix);
path_buf := make([]byte, len(prefix)+len(path)+len(`\`), context.temp_allocator)
copy(path_buf, prefix)
n := len(path)
r, w := 0, len(prefix)
for r < n {
switch {
case is_path_separator(path[r]):
r += 1;
r += 1
case path[r] == '.' && (r+1 == n || is_path_separator(path[r+1])):
r += 1;
r += 1
case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || is_path_separator(path[r+2])):
return path;
return path
case:
path_buf[w] = '\\';
w += 1;
path_buf[w] = '\\'
w += 1
for ; r < n && !is_path_separator(path[r]); r += 1 {
path_buf[w] = path[r];
w += 1;
path_buf[w] = path[r]
w += 1
}
}
}
if w == len(`\\?\c:`) {
path_buf[w] = '\\';
w += 1;
path_buf[w] = '\\'
w += 1
}
return string(path_buf[:w]);
return string(path_buf[:w])
}
link :: proc(old_name, new_name: string) -> Errno {
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));
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))
}
unlink :: proc(path: string) -> Errno {
wpath := win32.utf8_to_wstring(path, context.temp_allocator);
return Errno(win32.DeleteFileW(wpath));
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
return Errno(win32.DeleteFileW(wpath))
}
rename :: proc(old_path, new_path: string) -> Errno {
from := win32.utf8_to_wstring(old_path, context.temp_allocator);
to := win32.utf8_to_wstring(new_path, context.temp_allocator);
return Errno(win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING));
from := win32.utf8_to_wstring(old_path, context.temp_allocator)
to := win32.utf8_to_wstring(new_path, context.temp_allocator)
return Errno(win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING))
}
ftruncate :: proc(fd: Handle, length: i64) -> (err: Errno) {
curr_off, e := seek(fd, 0, 1);
curr_off, e := seek(fd, 0, 1)
if e != 0 {
return e;
return e
}
defer seek(fd, curr_off, 0);
_, e = seek(fd, length, 0);
defer seek(fd, curr_off, 0)
_, e = seek(fd, length, 0)
if e != 0 {
return e;
return e
}
ok := win32.SetEndOfFile(win32.HANDLE(fd));
ok := win32.SetEndOfFile(win32.HANDLE(fd))
if !ok {
return Errno(win32.GetLastError());
return Errno(win32.GetLastError())
}
return ERROR_NONE;
return ERROR_NONE
}
truncate :: proc(path: string, length: i64) -> (err: Errno) {
fd: Handle;
fd, err = open(path, O_WRONLY|O_CREATE, 0o666);
fd: Handle
fd, err = open(path, O_WRONLY|O_CREATE, 0o666)
if err != 0 {
return;
return
}
defer close(fd);
err = ftruncate(fd, length);
return;
defer close(fd)
err = ftruncate(fd, length)
return
}
remove :: proc(name: string) -> Errno {
p := win32.utf8_to_wstring(fix_long_path(name));
err, err1: win32.DWORD;
p := win32.utf8_to_wstring(fix_long_path(name))
err, err1: win32.DWORD
if !win32.DeleteFileW(p) {
err = win32.GetLastError();
err = win32.GetLastError()
}
if err == 0 {
return 0;
return 0
}
if !win32.RemoveDirectoryW(p) {
err1 = win32.GetLastError();
err1 = win32.GetLastError()
}
if err1 == 0 {
return 0;
return 0
}
if err != err1 {
a := win32.GetFileAttributesW(p);
a := win32.GetFileAttributesW(p)
if a == ~u32(0) {
err = win32.GetLastError();
err = win32.GetLastError()
} else {
if a & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
err = err1;
err = err1
} else if a & win32.FILE_ATTRIBUTE_READONLY != 0 {
if win32.SetFileAttributesW(p, a &~ win32.FILE_ATTRIBUTE_READONLY) {
err = 0;
err = 0
if !win32.DeleteFileW(p) {
err = win32.GetLastError();
err = win32.GetLastError()
}
}
}
}
}
return Errno(err);
return Errno(err)
}
pipe :: proc() -> (r, w: Handle, err: Errno) {
sa: win32.SECURITY_ATTRIBUTES;
sa.nLength = size_of(win32.SECURITY_ATTRIBUTES);
sa.bInheritHandle = true;
sa: win32.SECURITY_ATTRIBUTES
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 = Errno(win32.GetLastError())
}
return;
return
}
+84 -84
View File
@@ -5,130 +5,130 @@ import "core:strconv"
import "core:unicode/utf8"
OS :: ODIN_OS;
ARCH :: ODIN_ARCH;
ENDIAN :: ODIN_ENDIAN;
OS :: ODIN_OS
ARCH :: ODIN_ARCH
ENDIAN :: ODIN_ENDIAN
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
return write(fd, transmute([]byte)str);
return write(fd, transmute([]byte)str)
}
write_byte :: proc(fd: Handle, b: byte) -> (int, Errno) {
return write(fd, []byte{b});
return write(fd, []byte{b})
}
write_rune :: proc(fd: Handle, r: rune) -> (int, Errno) {
if r < utf8.RUNE_SELF {
return write_byte(fd, byte(r));
return write_byte(fd, byte(r))
}
b, n := utf8.encode_rune(r);
return write(fd, b[:n]);
b, n := utf8.encode_rune(r)
return write(fd, b[:n])
}
write_encoded_rune :: proc(fd: Handle, r: rune) {
write_byte(fd, '\'');
write_byte(fd, '\'')
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': 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:
if r < 32 {
write_string(fd, "\\x");
b: [2]byte;
s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil);
write_string(fd, "\\x")
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: write_string(fd, "00")
case 1: write_rune(fd, '0')
case 2: write_string(fd, s)
}
} else {
write_rune(fd, r);
write_rune(fd, r)
}
}
write_byte(fd, '\'');
write_byte(fd, '\'')
}
file_size_from_path :: proc(path: string) -> i64 {
fd, err := open(path, O_RDONLY, 0);
fd, err := open(path, O_RDONLY, 0)
if err != 0 {
return -1;
return -1
}
defer close(fd);
defer close(fd)
length: i64;
length: i64
if length, err = file_size(fd); err != 0 {
return -1;
return -1
}
return length;
return length
}
read_entire_file :: proc(name: string, allocator := context.allocator) -> (data: []byte, success: bool) {
fd, err := open(name, O_RDONLY, 0);
fd, err := open(name, O_RDONLY, 0)
if err != 0 {
return nil, false;
return nil, false
}
defer close(fd);
defer close(fd)
length: i64;
length: i64
if length, err = file_size(fd); err != 0 {
return nil, false;
return nil, false
}
if length <= 0 {
return nil, true;
return nil, true
}
data = make([]byte, int(length), allocator);
data = make([]byte, int(length), allocator)
if data == nil {
return nil, false;
return nil, false
}
bytes_read, read_err := read(fd, data);
bytes_read, read_err := read(fd, data)
if read_err != ERROR_NONE {
delete(data);
return nil, false;
delete(data)
return nil, false
}
return data[:bytes_read], true;
return data[:bytes_read], true
}
write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (success: bool) {
flags: int = O_WRONLY|O_CREATE;
flags: int = O_WRONLY|O_CREATE
if truncate {
flags |= O_TRUNC;
flags |= O_TRUNC
}
mode: int = 0;
mode: int = 0
when OS == "linux" || OS == "darwin" {
// NOTE(justasd): 644 (owner read, write; group read; others read)
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
}
fd, err := open(name, flags, mode);
fd, err := open(name, flags, mode)
if err != 0 {
return false;
return false
}
defer close(fd);
defer close(fd)
_, write_err := write(fd, data);
return write_err == 0;
_, write_err := write(fd, data)
return write_err == 0
}
write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
s := transmute([]byte)mem.Raw_Slice{data, len};
return write(fd, s);
s := transmute([]byte)mem.Raw_Slice{data, len}
return write(fd, s)
}
read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
s := transmute([]byte)mem.Raw_Slice{data, len};
return read(fd, s);
s := transmute([]byte)mem.Raw_Slice{data, len}
return read(fd, s)
}
heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
@@ -142,77 +142,77 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
//
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil) -> ([]byte, mem.Allocator_Error) {
a := max(alignment, align_of(rawptr));
space := size + a - 1;
a := max(alignment, align_of(rawptr))
space := size + a - 1
allocated_mem: rawptr;
allocated_mem: rawptr
if old_ptr != nil {
original_old_ptr := mem.ptr_offset((^rawptr)(old_ptr), -1)^;
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr));
original_old_ptr := mem.ptr_offset((^rawptr)(old_ptr), -1)^
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
} else {
allocated_mem = heap_alloc(space+size_of(rawptr));
allocated_mem = heap_alloc(space+size_of(rawptr))
}
aligned_mem := rawptr(mem.ptr_offset((^u8)(allocated_mem), size_of(rawptr)));
aligned_mem := rawptr(mem.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
ptr := uintptr(aligned_mem);
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a);
diff := int(aligned_ptr - ptr);
ptr := uintptr(aligned_mem)
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
diff := int(aligned_ptr - ptr)
if (size + diff) > space {
return nil, .Out_Of_Memory;
return nil, .Out_Of_Memory
}
aligned_mem = rawptr(aligned_ptr);
mem.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem;
aligned_mem = rawptr(aligned_ptr)
mem.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem
return mem.byte_slice(aligned_mem, size), nil;
return mem.byte_slice(aligned_mem, size), nil
}
aligned_free :: proc(p: rawptr) {
if p != nil {
heap_free(mem.ptr_offset((^rawptr)(p), -1)^);
heap_free(mem.ptr_offset((^rawptr)(p), -1)^)
}
}
aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> ([]byte, mem.Allocator_Error) {
if p == nil {
return nil, nil;
return nil, nil
}
return aligned_alloc(new_size, new_alignment, p);
return aligned_alloc(new_size, new_alignment, p)
}
switch mode {
case .Alloc:
return aligned_alloc(size, alignment);
return aligned_alloc(size, alignment)
case .Free:
aligned_free(old_memory);
aligned_free(old_memory)
case .Free_All:
return nil, .Mode_Not_Implemented;
return nil, .Mode_Not_Implemented
case .Resize:
if old_memory == nil {
return aligned_alloc(size, alignment);
return aligned_alloc(size, alignment)
}
return aligned_resize(old_memory, old_size, size, alignment);
return aligned_resize(old_memory, old_size, size, alignment)
case .Query_Features:
set := (^mem.Allocator_Mode_Set)(old_memory);
set := (^mem.Allocator_Mode_Set)(old_memory)
if set != nil {
set^ = {.Alloc, .Free, .Resize, .Query_Features};
set^ = {.Alloc, .Free, .Resize, .Query_Features}
}
return nil, nil;
return nil, nil
case .Query_Info:
return nil, .Mode_Not_Implemented;
return nil, .Mode_Not_Implemented
}
return nil, nil;
return nil, nil
}
heap_allocator :: proc() -> mem.Allocator {
return mem.Allocator{
procedure = heap_allocator_proc,
data = nil,
};
}
}
+101 -101
View File
@@ -3,161 +3,161 @@ package os
import win32 "core:sys/windows"
Handle :: distinct uintptr;
File_Time :: distinct u64;
Errno :: distinct int;
Handle :: distinct uintptr
File_Time :: distinct u64
Errno :: distinct int
INVALID_HANDLE :: ~Handle(0);
INVALID_HANDLE :: ~Handle(0)
O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001;
O_RDWR :: 0x00002;
O_CREATE :: 0x00040;
O_EXCL :: 0x00080;
O_NOCTTY :: 0x00100;
O_TRUNC :: 0x00200;
O_NONBLOCK :: 0x00800;
O_APPEND :: 0x00400;
O_SYNC :: 0x01000;
O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000;
O_RDONLY :: 0x00000
O_WRONLY :: 0x00001
O_RDWR :: 0x00002
O_CREATE :: 0x00040
O_EXCL :: 0x00080
O_NOCTTY :: 0x00100
O_TRUNC :: 0x00200
O_NONBLOCK :: 0x00800
O_APPEND :: 0x00400
O_SYNC :: 0x01000
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_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
// 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: Errno : 1<<29 + 0
ERROR_FILE_IS_NOT_DIR: Errno : 1<<29 + 1
ERROR_NEGATIVE_OFFSET: Errno : 1<<29 + 2
// "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments();
args := _alloc_command_line_arguments()
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
file_info: win32.BY_HANDLE_FILE_INFORMATION;
file_info: win32.BY_HANDLE_FILE_INFORMATION
if !win32.GetFileInformationByHandle(win32.HANDLE(fd), &file_info) {
return 0, Errno(win32.GetLastError());
return 0, Errno(win32.GetLastError())
}
lo := File_Time(file_info.ftLastWriteTime.dwLowDateTime);
hi := File_Time(file_info.ftLastWriteTime.dwHighDateTime);
return lo | hi << 32, ERROR_NONE;
lo := File_Time(file_info.ftLastWriteTime.dwLowDateTime)
hi := File_Time(file_info.ftLastWriteTime.dwHighDateTime)
return lo | hi << 32, ERROR_NONE
}
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
data: win32.WIN32_FILE_ATTRIBUTE_DATA;
data: win32.WIN32_FILE_ATTRIBUTE_DATA
wide_path := win32.utf8_to_wstring(name);
wide_path := win32.utf8_to_wstring(name)
if !win32.GetFileAttributesExW(wide_path, win32.GetFileExInfoStandard, &data) {
return 0, Errno(win32.GetLastError());
return 0, Errno(win32.GetLastError())
}
l := File_Time(data.ftLastWriteTime.dwLowDateTime);
h := File_Time(data.ftLastWriteTime.dwHighDateTime);
return l | h << 32, ERROR_NONE;
l := File_Time(data.ftLastWriteTime.dwLowDateTime)
h := File_Time(data.ftLastWriteTime.dwHighDateTime)
return l | h << 32, ERROR_NONE
}
heap_alloc :: proc(size: int) -> rawptr {
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, uint(size));
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, uint(size))
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 {
heap_free(ptr);
return nil;
heap_free(ptr)
return nil
}
if ptr == nil {
return heap_alloc(new_size);
return heap_alloc(new_size)
}
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, uint(new_size));
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, uint(new_size))
}
heap_free :: proc(ptr: rawptr) {
if ptr == nil {
return;
return
}
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
}
get_page_size :: proc() -> int {
// NOTE(tetra): The page size never changes, so why do anything complicated
// if we don't have to.
@static page_size := -1;
@static page_size := -1
if page_size != -1 {
return page_size;
return page_size
}
info: win32.SYSTEM_INFO;
win32.GetSystemInfo(&info);
page_size = int(info.dwPageSize);
return page_size;
info: win32.SYSTEM_INFO
win32.GetSystemInfo(&info)
page_size = int(info.dwPageSize)
return page_size
}
exit :: proc "contextless" (code: int) -> ! {
win32.ExitProcess(win32.DWORD(code));
win32.ExitProcess(win32.DWORD(code))
}
current_thread_id :: proc "contextless" () -> int {
return int(win32.GetCurrentThreadId());
return int(win32.GetCurrentThreadId())
}
_alloc_command_line_arguments :: proc() -> []string {
arg_count: i32;
arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count);
arg_list := make([]string, int(arg_count));
arg_count: i32
arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count)
arg_list := make([]string, int(arg_count))
for _, i in arg_list {
wc_str := (^win32.wstring)(uintptr(arg_list_ptr) + size_of(win32.wstring)*uintptr(i))^;
wc_str := (^win32.wstring)(uintptr(arg_list_ptr) + size_of(win32.wstring)*uintptr(i))^
olen := win32.WideCharToMultiByte(win32.CP_UTF8, 0, wc_str, -1,
nil, 0, nil, nil);
nil, 0, nil, nil)
buf := make([]byte, int(olen));
buf := make([]byte, int(olen))
n := win32.WideCharToMultiByte(win32.CP_UTF8, 0, wc_str, -1,
raw_data(buf), olen, nil, nil);
raw_data(buf), olen, nil, nil)
if n > 0 {
n -= 1;
n -= 1
}
arg_list[i] = string(buf[:n]);
arg_list[i] = string(buf[:n])
}
return arg_list;
return arg_list
}
/*
@@ -170,46 +170,46 @@ _alloc_command_line_arguments :: proc() -> []string {
TODO: Narrow down this range once Win 11 is published and the last Win 10 builds
become available.
*/
WINDOWS_11_BUILD_CUTOFF :: 22_000;
WINDOWS_11_BUILD_CUTOFF :: 22_000
get_windows_version_w :: proc() -> win32.OSVERSIONINFOEXW {
osvi : win32.OSVERSIONINFOEXW;
osvi.dwOSVersionInfoSize = size_of(win32.OSVERSIONINFOEXW);
win32.RtlGetVersion(&osvi);
return osvi;
osvi : win32.OSVERSIONINFOEXW
osvi.dwOSVersionInfoSize = size_of(win32.OSVERSIONINFOEXW)
win32.RtlGetVersion(&osvi)
return osvi
}
is_windows_xp :: proc() -> bool {
osvi := get_windows_version_w();
return (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1);
osvi := get_windows_version_w()
return (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
}
is_windows_vista :: proc() -> bool {
osvi := get_windows_version_w();
return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0);
osvi := get_windows_version_w()
return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
}
is_windows_7 :: proc() -> bool {
osvi := get_windows_version_w();
return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1);
osvi := get_windows_version_w()
return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
}
is_windows_8 :: proc() -> bool {
osvi := get_windows_version_w();
return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2);
osvi := get_windows_version_w()
return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2)
}
is_windows_8_1 :: proc() -> bool {
osvi := get_windows_version_w();
return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3);
osvi := get_windows_version_w()
return (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3)
}
is_windows_10 :: proc() -> bool {
osvi := get_windows_version_w();
return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber < WINDOWS_11_BUILD_CUTOFF);
osvi := get_windows_version_w()
return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber < WINDOWS_11_BUILD_CUTOFF)
}
is_windows_11 :: proc() -> bool {
osvi := get_windows_version_w();
return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= WINDOWS_11_BUILD_CUTOFF);
osvi := get_windows_version_w()
return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= WINDOWS_11_BUILD_CUTOFF)
}
+9 -9
View File
@@ -16,19 +16,19 @@ File_Info :: struct {
file_info_slice_delete :: proc(infos: []File_Info, allocator := context.allocator) {
for i := len(infos)-1; i >= 0; i -= 1 {
file_info_delete(infos[i], allocator);
file_info_delete(infos[i], allocator)
}
delete(infos, allocator);
delete(infos, allocator)
}
file_info_delete :: proc(fi: File_Info, allocator := context.allocator) {
delete(fi.fullpath, allocator);
delete(fi.fullpath, allocator)
}
File_Mode :: distinct u32;
File_Mode :: distinct u32
File_Mode_Dir :: File_Mode(1<<16);
File_Mode_Named_Pipe :: File_Mode(1<<17);
File_Mode_Device :: File_Mode(1<<18);
File_Mode_Char_Device :: File_Mode(1<<19);
File_Mode_Sym_Link :: File_Mode(1<<20);
File_Mode_Dir :: File_Mode(1<<16)
File_Mode_Named_Pipe :: File_Mode(1<<17)
File_Mode_Device :: File_Mode(1<<18)
File_Mode_Char_Device :: File_Mode(1<<19)
File_Mode_Sym_Link :: File_Mode(1<<20)
+131 -131
View File
@@ -5,312 +5,312 @@ import win32 "core:sys/windows"
@(private)
full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Errno) {
name := name;
name := name
if name == "" {
name = ".";
name = "."
}
p := win32.utf8_to_utf16(name, context.temp_allocator);
buf := make([dynamic]u16, 100, allocator);
defer delete(buf);
p := win32.utf8_to_utf16(name, context.temp_allocator)
buf := make([dynamic]u16, 100, allocator)
defer delete(buf)
for {
n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil);
n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
if n == 0 {
return "", Errno(win32.GetLastError());
return "", Errno(win32.GetLastError())
}
if n <= u32(len(buf)) {
return win32.utf16_to_utf8(buf[:n], allocator), ERROR_NONE;
return win32.utf16_to_utf8(buf[:n], allocator), ERROR_NONE
}
resize(&buf, len(buf)*2);
resize(&buf, len(buf)*2)
}
return;
return
}
@(private)
_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;
return {}, ERROR_PATH_NOT_FOUND
}
context.allocator = allocator;
context.allocator = allocator
wname := win32.utf8_to_wstring(fix_long_path(name), context.temp_allocator);
fa: win32.WIN32_FILE_ATTRIBUTE_DATA;
ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa);
wname := win32.utf8_to_wstring(fix_long_path(name), context.temp_allocator)
fa: win32.WIN32_FILE_ATTRIBUTE_DATA
ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa)
if ok && fa.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
// Not a symlink
return file_info_from_win32_file_attribute_data(&fa, name);
return file_info_from_win32_file_attribute_data(&fa, name)
}
err := 0 if ok else win32.GetLastError();
err := 0 if ok else win32.GetLastError()
if err == win32.ERROR_SHARING_VIOLATION {
fd: win32.WIN32_FIND_DATAW;
sh := win32.FindFirstFileW(wname, &fd);
fd: win32.WIN32_FIND_DATAW
sh := win32.FindFirstFileW(wname, &fd)
if sh == win32.INVALID_HANDLE_VALUE {
e = Errno(win32.GetLastError());
return;
e = Errno(win32.GetLastError())
return
}
win32.FindClose(sh);
win32.FindClose(sh)
return file_info_from_win32_find_data(&fd, name);
return file_info_from_win32_find_data(&fd, name)
}
h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil);
h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil)
if h == win32.INVALID_HANDLE_VALUE {
e = Errno(win32.GetLastError());
return;
e = Errno(win32.GetLastError())
return
}
defer win32.CloseHandle(h);
return file_info_from_get_file_information_by_handle(name, h);
defer win32.CloseHandle(h)
return file_info_from_get_file_information_by_handle(name, h)
}
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);
attrs := win32.FILE_FLAG_BACKUP_SEMANTICS
attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT
return _stat(name, attrs, allocator)
}
stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) {
attrs := win32.FILE_FLAG_BACKUP_SEMANTICS;
return _stat(name, attrs, allocator);
attrs := win32.FILE_FLAG_BACKUP_SEMANTICS
return _stat(name, attrs, allocator)
}
fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Errno) {
if fd == 0 {
return {}, ERROR_INVALID_HANDLE;
return {}, ERROR_INVALID_HANDLE
}
context.allocator = allocator;
context.allocator = allocator
path, err := cleanpath_from_handle(fd);
path, err := cleanpath_from_handle(fd)
if err != ERROR_NONE {
return {}, err;
return {}, err
}
h := win32.HANDLE(fd);
h := win32.HANDLE(fd)
switch win32.GetFileType(h) {
case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
fi: File_Info;
fi.fullpath = path;
fi.name = basename(path);
fi.mode |= file_type_mode(h);
return fi, ERROR_NONE;
fi: File_Info
fi.fullpath = path
fi.name = basename(path)
fi.mode |= file_type_mode(h)
return fi, ERROR_NONE
}
return file_info_from_get_file_information_by_handle(path, h);
return file_info_from_get_file_information_by_handle(path, h)
}
@(private)
cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
buf := buf;
N := 0;
buf := buf
N := 0
for c, i in buf {
if c == 0 { break; }
N = i+1;
N = i+1
}
buf = buf[:N];
buf = buf[:N]
if len(buf) >= 4 {
if buf[0] == '\\' &&
buf[1] == '\\' &&
buf[2] == '?' &&
buf[3] == '\\' {
buf = buf[4:];
buf = buf[4:]
}
}
return buf;
return buf
}
@(private)
cleanpath_from_handle :: proc(fd: Handle) -> (string, Errno) {
if fd == 0 {
return "", ERROR_INVALID_HANDLE;
return "", ERROR_INVALID_HANDLE
}
h := win32.HANDLE(fd);
h := win32.HANDLE(fd)
MAX_PATH := win32.DWORD(260) + 1;
buf: []u16;
MAX_PATH := win32.DWORD(260) + 1
buf: []u16
for {
buf = make([]u16, MAX_PATH, context.temp_allocator);
err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0);
buf = make([]u16, MAX_PATH, context.temp_allocator)
err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0)
switch Errno(err) {
case ERROR_PATH_NOT_FOUND, ERROR_INVALID_PARAMETER:
return "", Errno(err);
return "", Errno(err)
case ERROR_NOT_ENOUGH_MEMORY:
MAX_PATH = MAX_PATH*2 + 1;
continue;
MAX_PATH = MAX_PATH*2 + 1
continue
}
break;
break
}
return cleanpath_from_buf(buf), ERROR_NONE;
return cleanpath_from_buf(buf), ERROR_NONE
}
@(private)
cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) {
if fd == 0 {
return nil, ERROR_INVALID_HANDLE;
return nil, ERROR_INVALID_HANDLE
}
h := win32.HANDLE(fd);
h := win32.HANDLE(fd)
MAX_PATH := win32.DWORD(260) + 1;
buf: []u16;
MAX_PATH := win32.DWORD(260) + 1
buf: []u16
for {
buf = make([]u16, MAX_PATH, context.temp_allocator);
err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0);
buf = make([]u16, MAX_PATH, context.temp_allocator)
err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0)
switch Errno(err) {
case ERROR_PATH_NOT_FOUND, ERROR_INVALID_PARAMETER:
return nil, Errno(err);
return nil, Errno(err)
case ERROR_NOT_ENOUGH_MEMORY:
MAX_PATH = MAX_PATH*2 + 1;
continue;
MAX_PATH = MAX_PATH*2 + 1
continue
}
break;
break
}
return cleanpath_strip_prefix(buf), ERROR_NONE;
return cleanpath_strip_prefix(buf), ERROR_NONE
}
@(private)
cleanpath_from_buf :: proc(buf: []u16) -> string {
buf := buf;
buf = cleanpath_strip_prefix(buf);
return win32.utf16_to_utf8(buf, context.allocator);
buf := buf
buf = cleanpath_strip_prefix(buf)
return win32.utf16_to_utf8(buf, context.allocator)
}
@(private)
basename :: proc(name: string) -> (base: string) {
name := name;
name := name
if len(name) > 3 && name[:3] == `\\?` {
name = name[3:];
name = name[3:]
}
if len(name) == 2 && name[1] == ':' {
return ".";
return "."
} else if len(name) > 2 && name[1] == ':' {
name = name[2:];
name = name[2:]
}
i := len(name)-1;
i := len(name)-1
for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i -= 1 {
name = name[:i];
name = name[:i]
}
for i -= 1; i >= 0; i -= 1 {
if name[i] == '/' || name[i] == '\\' {
name = name[i+1:];
break;
name = name[i+1:]
break
}
}
return name;
return name
}
@(private)
file_type_mode :: proc(h: win32.HANDLE) -> File_Mode {
switch win32.GetFileType(h) {
case win32.FILE_TYPE_PIPE:
return File_Mode_Named_Pipe;
return File_Mode_Named_Pipe
case win32.FILE_TYPE_CHAR:
return File_Mode_Device | File_Mode_Char_Device;
return File_Mode_Device | File_Mode_Char_Device
}
return 0;
return 0
}
@(private)
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;
mode |= 0o444
} else {
mode |= 0o666;
mode |= 0o666
}
is_sym := false;
is_sym := false
if FileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
is_sym = false;
is_sym = false
} else {
is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT;
is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT
}
if is_sym {
mode |= File_Mode_Sym_Link;
mode |= File_Mode_Sym_Link
} else {
if FileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
mode |= 0o111 | File_Mode_Dir;
mode |= 0o111 | File_Mode_Dir
}
if h != nil {
mode |= file_type_mode(h);
mode |= file_type_mode(h)
}
}
return;
return
}
@(private)
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);
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0);
fi.is_dir = fi.mode & File_Mode_Dir != 0;
fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
fi.is_dir = fi.mode & File_Mode_Dir != 0
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));
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))
fi.fullpath, e = full_path_from_name(name);
fi.name = basename(fi.fullpath);
fi.fullpath, e = full_path_from_name(name)
fi.name = basename(fi.fullpath)
return;
return
}
@(private)
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);
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0);
fi.is_dir = fi.mode & File_Mode_Dir != 0;
fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
fi.is_dir = fi.mode & File_Mode_Dir != 0
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));
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))
fi.fullpath, e = full_path_from_name(name);
fi.name = basename(fi.fullpath);
fi.fullpath, e = full_path_from_name(name)
fi.name = basename(fi.fullpath)
return;
return
}
@(private)
file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Errno) {
d: win32.BY_HANDLE_FILE_INFORMATION;
d: win32.BY_HANDLE_FILE_INFORMATION
if !win32.GetFileInformationByHandle(h, &d) {
err := Errno(win32.GetLastError());
return {}, err;
err := Errno(win32.GetLastError())
return {}, err
}
ti: win32.FILE_ATTRIBUTE_TAG_INFO;
ti: win32.FILE_ATTRIBUTE_TAG_INFO
if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) {
err := win32.GetLastError();
err := win32.GetLastError()
if err != u32(ERROR_INVALID_PARAMETER) {
return {}, Errno(err);
return {}, Errno(err)
}
// Indicate this is a symlink on FAT file systems
ti.ReparseTag = 0;
ti.ReparseTag = 0
}
fi: File_Info;
fi: File_Info
fi.fullpath = path;
fi.name = basename(path);
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow);
fi.fullpath = path
fi.name = basename(path)
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
fi.mode |= file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag);
fi.is_dir = fi.mode & File_Mode_Dir != 0;
fi.mode |= file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag)
fi.is_dir = fi.mode & File_Mode_Dir != 0
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));
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))
return fi, ERROR_NONE;
return fi, ERROR_NONE
}
+35 -35
View File
@@ -3,67 +3,67 @@ package os
import "core:io"
stream_from_handle :: proc(fd: Handle) -> io.Stream {
s: io.Stream;
s.stream_data = rawptr(uintptr(fd));
s.stream_vtable = _file_stream_vtable;
return s;
s: io.Stream
s.stream_data = rawptr(uintptr(fd))
s.stream_vtable = _file_stream_vtable
return s
}
@(private)
_file_stream_vtable := &io.Stream_VTable{
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
fd := Handle(uintptr(s.stream_data));
os_err: Errno;
n, os_err = read(fd, p);
return;
fd := Handle(uintptr(s.stream_data))
os_err: Errno
n, os_err = read(fd, p)
return
},
impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
when ODIN_OS == "windows" {
fd := Handle(uintptr(s.stream_data));
os_err: Errno;
n, os_err = read_at(fd, p, offset);
fd := Handle(uintptr(s.stream_data))
os_err: Errno
n, os_err = read_at(fd, p, offset)
}
return;
return
},
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
fd := Handle(uintptr(s.stream_data));
os_err: Errno;
n, os_err = write(fd, p);
return;
fd := Handle(uintptr(s.stream_data))
os_err: Errno
n, os_err = write(fd, p)
return
},
impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
when ODIN_OS == "windows" {
fd := Handle(uintptr(s.stream_data));
os_err: Errno;
n, os_err = write_at(fd, p, offset);
_ = os_err;
fd := Handle(uintptr(s.stream_data))
os_err: Errno
n, os_err = write_at(fd, p, offset)
_ = os_err
}
return;
return
},
impl_seek = proc(s: io.Stream, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
fd := Handle(uintptr(s.stream_data));
n, os_err := seek(fd, offset, int(whence));
_ = os_err;
return n, nil;
fd := Handle(uintptr(s.stream_data))
n, os_err := seek(fd, offset, int(whence))
_ = os_err
return n, nil
},
impl_size = proc(s: io.Stream) -> i64 {
fd := Handle(uintptr(s.stream_data));
sz, _ := file_size(fd);
return sz;
fd := Handle(uintptr(s.stream_data))
sz, _ := file_size(fd)
return sz
},
impl_flush = proc(s: io.Stream) -> io.Error {
when ODIN_OS == "windows" {
fd := Handle(uintptr(s.stream_data));
flush(fd);
fd := Handle(uintptr(s.stream_data))
flush(fd)
} else {
// TOOD(bill): other operating systems
}
return nil;
return nil
},
impl_close = proc(s: io.Stream) -> io.Error {
fd := Handle(uintptr(s.stream_data));
close(fd);
return nil;
fd := Handle(uintptr(s.stream_data))
close(fd)
return nil
},
};
}