mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Remove unneeded semicolons from the core library
This commit is contained in:
+48
-48
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user