Get Odin to compile on Haiku

This patch makes Odin to compile on Haiku which is a good first step.
Now, all that's needed to do is to figure out how to do futexes, which
I am blaming for the program crashing.
This commit is contained in:
Slendi
2024-02-15 15:51:28 +02:00
parent c5c2a4d09d
commit c178f7199d
4 changed files with 559 additions and 464 deletions
+5
View File
@@ -83,6 +83,11 @@ OpenBSD)
LDFLAGS="$LDFLAGS -liconv" LDFLAGS="$LDFLAGS -liconv"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
;; ;;
Haiku)
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags) -I/system/develop/headers/private/shared -I/system/develop/headers/private/kernel"
LDFLAGS="$LDFLAGS -liconv"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
;;
*) *)
error "Platform \"$OS_NAME\" unsupported" error "Platform \"$OS_NAME\" unsupported"
;; ;;
+47 -2
View File
@@ -83,6 +83,10 @@ extern "C" {
#ifndef GB_SYSTEM_OPENBSD #ifndef GB_SYSTEM_OPENBSD
#define GB_SYSTEM_OPENBSD 1 #define GB_SYSTEM_OPENBSD 1
#endif #endif
#elif defined(__HAIKU__) || defined(__haiku__)
#ifndef GB_SYSTEM_HAIKU
#define GB_SYSTEM_HAIKU 1
#endif
#else #else
#error This UNIX operating system is not supported #error This UNIX operating system is not supported
#endif #endif
@@ -206,7 +210,7 @@ extern "C" {
#endif #endif
#include <stdlib.h> // NOTE(bill): malloc on linux #include <stdlib.h> // NOTE(bill): malloc on linux
#include <sys/mman.h> #include <sys/mman.h>
#if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) #if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__HAIKU__)
#include <sys/sendfile.h> #include <sys/sendfile.h>
#endif #endif
#include <sys/stat.h> #include <sys/stat.h>
@@ -247,6 +251,13 @@ extern "C" {
#include <pthread_np.h> #include <pthread_np.h>
#define lseek64 lseek #define lseek64 lseek
#endif #endif
#if defined(GB_SYSTEM_HAIKU)
#include <stdio.h>
#include <pthread.h>
#include <kernel/OS.h>
#define lseek64 lseek
#endif
#if defined(GB_SYSTEM_UNIX) #if defined(GB_SYSTEM_UNIX)
#include <semaphore.h> #include <semaphore.h>
@@ -801,6 +812,13 @@ typedef struct gbAffinity {
isize thread_count; isize thread_count;
isize threads_per_core; isize threads_per_core;
} gbAffinity; } gbAffinity;
#elif defined(GB_SYSTEM_HAIKU)
typedef struct gbAffinity {
b32 is_accurate;
isize core_count;
isize thread_count;
isize threads_per_core;
} gbAffinity;
#else #else
#error TODO(bill): Unknown system #error TODO(bill): Unknown system
#endif #endif
@@ -2984,6 +3002,8 @@ gb_inline u32 gb_thread_current_id(void) {
__asm__("mov %%fs:0x10,%0" : "=r"(thread_id)); __asm__("mov %%fs:0x10,%0" : "=r"(thread_id));
#elif defined(GB_SYSTEM_LINUX) #elif defined(GB_SYSTEM_LINUX)
thread_id = gettid(); thread_id = gettid();
#elif defined(GB_SYSTEM_HAIKU)
thread_id = find_thread(NULL);
#else #else
#error Unsupported architecture for gb_thread_current_id() #error Unsupported architecture for gb_thread_current_id()
#endif #endif
@@ -3184,7 +3204,9 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
//info.affinity_tag = cast(integer_t)index; //info.affinity_tag = cast(integer_t)index;
//result = thread_policy_set(thread, THREAD_AFFINITY_POLICY, cast(thread_policy_t)&info, THREAD_AFFINITY_POLICY_COUNT); //result = thread_policy_set(thread, THREAD_AFFINITY_POLICY, cast(thread_policy_t)&info, THREAD_AFFINITY_POLICY_COUNT);
#if !defined(GB_SYSTEM_HAIKU)
result = pthread_setaffinity_np(thread, sizeof(cpuset_t), &mn); result = pthread_setaffinity_np(thread, sizeof(cpuset_t), &mn);
#endif
return result == 0; return result == 0;
} }
@@ -3236,6 +3258,29 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
return true; return true;
} }
isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
GB_ASSERT(0 <= core && core < a->core_count);
return a->threads_per_core;
}
#elif defined(GB_SYSTEM_HAIKU)
#include <unistd.h>
void gb_affinity_init(gbAffinity *a) {
a->core_count = sysconf(_SC_NPROCESSORS_ONLN);
a->threads_per_core = 1;
a->is_accurate = a->core_count > 0;
a->core_count = a->is_accurate ? a->core_count : 1;
a->thread_count = a->core_count;
}
void gb_affinity_destroy(gbAffinity *a) {
gb_unused(a);
}
b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
return true;
}
isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
GB_ASSERT(0 <= core && core < a->core_count); GB_ASSERT(0 <= core && core < a->core_count);
return a->threads_per_core; return a->threads_per_core;
@@ -5457,7 +5502,7 @@ gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filena
} }
} }
gb_free(buf); gb_mfree(buf);
close(new_fd); close(new_fd);
close(existing_fd); close(existing_fd);
+461 -461
View File
@@ -1,461 +1,461 @@
/* /*
Path handling utilities. Path handling utilities.
*/ */
#if !defined(GB_SYSTEM_WINDOWS) #if !defined(GB_SYSTEM_WINDOWS)
#include <unistd.h> #include <unistd.h>
#endif #endif
gb_internal String remove_extension_from_path(String const &s) { gb_internal String remove_extension_from_path(String const &s) {
if (s.len != 0 && s.text[s.len-1] == '.') { if (s.len != 0 && s.text[s.len-1] == '.') {
return s; return s;
} }
for (isize i = s.len-1; i >= 0; i--) { for (isize i = s.len-1; i >= 0; i--) {
if (s[i] == '.') { if (s[i] == '.') {
return substring(s, 0, i); return substring(s, 0, i);
} }
} }
return s; return s;
} }
gb_internal String remove_directory_from_path(String const &s) { gb_internal String remove_directory_from_path(String const &s) {
isize len = 0; isize len = 0;
for (isize i = s.len-1; i >= 0; i--) { for (isize i = s.len-1; i >= 0; i--) {
if (s[i] == '/' || if (s[i] == '/' ||
s[i] == '\\') { s[i] == '\\') {
break; break;
} }
len += 1; len += 1;
} }
return substring(s, s.len-len, s.len); return substring(s, s.len-len, s.len);
} }
// NOTE(Mark Naughton): getcwd as String // NOTE(Mark Naughton): getcwd as String
#if !defined(GB_SYSTEM_WINDOWS) #if !defined(GB_SYSTEM_WINDOWS)
gb_internal String get_current_directory(void) { gb_internal String get_current_directory(void) {
char cwd[256]; char cwd[256];
getcwd(cwd, 256); getcwd(cwd, 256);
return make_string_c(cwd); return make_string_c(cwd);
} }
#else #else
gb_internal String get_current_directory(void) { gb_internal String get_current_directory(void) {
gbAllocator a = heap_allocator(); gbAllocator a = heap_allocator();
wchar_t cwd[256]; wchar_t cwd[256];
GetCurrentDirectoryW(256, cwd); GetCurrentDirectoryW(256, cwd);
String16 wstr = make_string16_c(cwd); String16 wstr = make_string16_c(cwd);
return string16_to_string(a, wstr); return string16_to_string(a, wstr);
} }
#endif #endif
gb_internal bool path_is_directory(String path); gb_internal bool path_is_directory(String path);
gb_internal String directory_from_path(String const &s) { gb_internal String directory_from_path(String const &s) {
if (path_is_directory(s)) { if (path_is_directory(s)) {
return s; return s;
} }
isize i = s.len-1; isize i = s.len-1;
for (; i >= 0; i--) { for (; i >= 0; i--) {
if (s[i] == '/' || if (s[i] == '/' ||
s[i] == '\\') { s[i] == '\\') {
break; break;
} }
} }
if (i >= 0) { if (i >= 0) {
return substring(s, 0, i); return substring(s, 0, i);
} }
return substring(s, 0, 0); return substring(s, 0, 0);
} }
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
gb_internal bool path_is_directory(String path) { gb_internal bool path_is_directory(String path) {
gbAllocator a = heap_allocator(); gbAllocator a = heap_allocator();
String16 wstr = string_to_string16(a, path); String16 wstr = string_to_string16(a, path);
defer (gb_free(a, wstr.text)); defer (gb_free(a, wstr.text));
i32 attribs = GetFileAttributesW(wstr.text); i32 attribs = GetFileAttributesW(wstr.text);
if (attribs < 0) return false; if (attribs < 0) return false;
return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
} }
#else #else
gb_internal bool path_is_directory(String path) { gb_internal bool path_is_directory(String path) {
gbAllocator a = heap_allocator(); gbAllocator a = heap_allocator();
char *copy = cast(char *)copy_string(a, path).text; char *copy = cast(char *)copy_string(a, path).text;
defer (gb_free(a, copy)); defer (gb_free(a, copy));
struct stat s; struct stat s;
if (stat(copy, &s) == 0) { if (stat(copy, &s) == 0) {
return (s.st_mode & S_IFDIR) != 0; return (s.st_mode & S_IFDIR) != 0;
} }
return false; return false;
} }
#endif #endif
gb_internal String path_to_full_path(gbAllocator a, String path) { gb_internal String path_to_full_path(gbAllocator a, String path) {
gbAllocator ha = heap_allocator(); gbAllocator ha = heap_allocator();
char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len); char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len);
defer (gb_free(ha, path_c)); defer (gb_free(ha, path_c));
char *fullpath = gb_path_get_full_name(a, path_c); char *fullpath = gb_path_get_full_name(a, path_c);
String res = string_trim_whitespace(make_string_c(fullpath)); String res = string_trim_whitespace(make_string_c(fullpath));
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
for (isize i = 0; i < res.len; i++) { for (isize i = 0; i < res.len; i++) {
if (res.text[i] == '\\') { if (res.text[i] == '\\') {
res.text[i] = '/'; res.text[i] = '/';
} }
} }
#endif #endif
return copy_string(a, res); return copy_string(a, res);
} }
struct Path { struct Path {
String basename; String basename;
String name; String name;
String ext; String ext;
}; };
// NOTE(Jeroen): Naively turns a Path into a string. // NOTE(Jeroen): Naively turns a Path into a string.
gb_internal String path_to_string(gbAllocator a, Path path) { gb_internal String path_to_string(gbAllocator a, Path path) {
if (path.basename.len + path.name.len + path.ext.len == 0) { if (path.basename.len + path.name.len + path.ext.len == 0) {
return make_string(nullptr, 0); return make_string(nullptr, 0);
} }
isize len = path.basename.len + 1 + path.name.len + 1; isize len = path.basename.len + 1 + path.name.len + 1;
if (path.ext.len > 0) { if (path.ext.len > 0) {
len += path.ext.len + 1; len += path.ext.len + 1;
} }
u8 *str = gb_alloc_array(a, u8, len); u8 *str = gb_alloc_array(a, u8, len);
isize i = 0; isize i = 0;
gb_memmove(str+i, path.basename.text, path.basename.len); i += path.basename.len; gb_memmove(str+i, path.basename.text, path.basename.len); i += path.basename.len;
gb_memmove(str+i, "/", 1); i += 1; gb_memmove(str+i, "/", 1); i += 1;
gb_memmove(str+i, path.name.text, path.name.len); i += path.name.len; gb_memmove(str+i, path.name.text, path.name.len); i += path.name.len;
if (path.ext.len > 0) { if (path.ext.len > 0) {
gb_memmove(str+i, ".", 1); i += 1; gb_memmove(str+i, ".", 1); i += 1;
gb_memmove(str+i, path.ext.text, path.ext.len); i += path.ext.len; gb_memmove(str+i, path.ext.text, path.ext.len); i += path.ext.len;
} }
str[i] = 0; str[i] = 0;
String res = make_string(str, i); String res = make_string(str, i);
res = string_trim_whitespace(res); res = string_trim_whitespace(res);
return res; return res;
} }
// NOTE(Jeroen): Naively turns a Path into a string, then normalizes it using `path_to_full_path`. // NOTE(Jeroen): Naively turns a Path into a string, then normalizes it using `path_to_full_path`.
gb_internal String path_to_full_path(gbAllocator a, Path path) { gb_internal String path_to_full_path(gbAllocator a, Path path) {
String temp = path_to_string(heap_allocator(), path); String temp = path_to_string(heap_allocator(), path);
defer (gb_free(heap_allocator(), temp.text)); defer (gb_free(heap_allocator(), temp.text));
return path_to_full_path(a, temp); return path_to_full_path(a, temp);
} }
// NOTE(Jeroen): Takes a path like "odin" or "W:\Odin", turns it into a full path, // NOTE(Jeroen): Takes a path like "odin" or "W:\Odin", turns it into a full path,
// and then breaks it into its components to make a Path. // and then breaks it into its components to make a Path.
gb_internal Path path_from_string(gbAllocator a, String const &path) { gb_internal Path path_from_string(gbAllocator a, String const &path) {
Path res = {}; Path res = {};
if (path.len == 0) return res; if (path.len == 0) return res;
String fullpath = path_to_full_path(a, path); String fullpath = path_to_full_path(a, path);
defer (gb_free(heap_allocator(), fullpath.text)); defer (gb_free(heap_allocator(), fullpath.text));
res.basename = directory_from_path(fullpath); res.basename = directory_from_path(fullpath);
res.basename = copy_string(a, res.basename); res.basename = copy_string(a, res.basename);
if (path_is_directory(fullpath)) { if (path_is_directory(fullpath)) {
// It's a directory. We don't need to tinker with the name and extension. // It's a directory. We don't need to tinker with the name and extension.
// It could have a superfluous trailing `/`. Remove it if so. // It could have a superfluous trailing `/`. Remove it if so.
if (res.basename.len > 0 && res.basename.text[res.basename.len - 1] == '/') { if (res.basename.len > 0 && res.basename.text[res.basename.len - 1] == '/') {
res.basename.len--; res.basename.len--;
} }
return res; return res;
} }
// Note(Dragos): Is the copy_string required if it's a substring? // Note(Dragos): Is the copy_string required if it's a substring?
isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len; isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len;
res.name = substring(fullpath, name_start, fullpath.len); res.name = substring(fullpath, name_start, fullpath.len);
res.name = remove_extension_from_path(res.name); res.name = remove_extension_from_path(res.name);
res.name = copy_string(a, res.name); res.name = copy_string(a, res.name);
res.ext = path_extension(fullpath, false); // false says not to include the dot. res.ext = path_extension(fullpath, false); // false says not to include the dot.
res.ext = copy_string(a, res.ext); res.ext = copy_string(a, res.ext);
return res; return res;
} }
// NOTE(Jeroen): Takes a path String and returns the last path element. // NOTE(Jeroen): Takes a path String and returns the last path element.
gb_internal String last_path_element(String const &path) { gb_internal String last_path_element(String const &path) {
isize count = 0; isize count = 0;
u8 * start = (u8 *)(&path.text[path.len - 1]); u8 * start = (u8 *)(&path.text[path.len - 1]);
for (isize length = path.len; length > 0 && path.text[length - 1] != '/'; length--) { for (isize length = path.len; length > 0 && path.text[length - 1] != '/'; length--) {
count++; count++;
start--; start--;
} }
if (count > 0) { if (count > 0) {
start++; // Advance past the `/` and return the substring. start++; // Advance past the `/` and return the substring.
String res = make_string(start, count); String res = make_string(start, count);
return res; return res;
} }
// Must be a root path like `/` or `C:/`, return empty String. // Must be a root path like `/` or `C:/`, return empty String.
return STR_LIT(""); return STR_LIT("");
} }
gb_internal bool path_is_directory(Path path) { gb_internal bool path_is_directory(Path path) {
String path_string = path_to_full_path(heap_allocator(), path); String path_string = path_to_full_path(heap_allocator(), path);
defer (gb_free(heap_allocator(), path_string.text)); defer (gb_free(heap_allocator(), path_string.text));
return path_is_directory(path_string); return path_is_directory(path_string);
} }
struct FileInfo { struct FileInfo {
String name; String name;
String fullpath; String fullpath;
i64 size; i64 size;
bool is_dir; bool is_dir;
}; };
enum ReadDirectoryError { enum ReadDirectoryError {
ReadDirectory_None, ReadDirectory_None,
ReadDirectory_InvalidPath, ReadDirectory_InvalidPath,
ReadDirectory_NotExists, ReadDirectory_NotExists,
ReadDirectory_Permission, ReadDirectory_Permission,
ReadDirectory_NotDir, ReadDirectory_NotDir,
ReadDirectory_Empty, ReadDirectory_Empty,
ReadDirectory_Unknown, ReadDirectory_Unknown,
ReadDirectory_COUNT, ReadDirectory_COUNT,
}; };
gb_internal i64 get_file_size(String path) { gb_internal i64 get_file_size(String path) {
char *c_str = alloc_cstring(heap_allocator(), path); char *c_str = alloc_cstring(heap_allocator(), path);
defer (gb_free(heap_allocator(), c_str)); defer (gb_free(heap_allocator(), c_str));
gbFile f = {}; gbFile f = {};
gbFileError err = gb_file_open(&f, c_str); gbFileError err = gb_file_open(&f, c_str);
defer (gb_file_close(&f)); defer (gb_file_close(&f));
if (err != gbFileError_None) { if (err != gbFileError_None) {
return -1; return -1;
} }
return gb_file_size(&f); return gb_file_size(&f);
} }
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) { gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
GB_ASSERT(fi != nullptr); GB_ASSERT(fi != nullptr);
while (path.len > 0) { while (path.len > 0) {
Rune end = path[path.len-1]; Rune end = path[path.len-1];
if (end == '/') { if (end == '/') {
path.len -= 1; path.len -= 1;
} else if (end == '\\') { } else if (end == '\\') {
path.len -= 1; path.len -= 1;
} else { } else {
break; break;
} }
} }
if (path.len == 0) { if (path.len == 0) {
return ReadDirectory_InvalidPath; return ReadDirectory_InvalidPath;
} }
{ {
char *c_str = alloc_cstring(temporary_allocator(), path); char *c_str = alloc_cstring(temporary_allocator(), path);
gbFile f = {}; gbFile f = {};
gbFileError file_err = gb_file_open(&f, c_str); gbFileError file_err = gb_file_open(&f, c_str);
defer (gb_file_close(&f)); defer (gb_file_close(&f));
switch (file_err) { switch (file_err) {
case gbFileError_Invalid: return ReadDirectory_InvalidPath; case gbFileError_Invalid: return ReadDirectory_InvalidPath;
case gbFileError_NotExists: return ReadDirectory_NotExists; case gbFileError_NotExists: return ReadDirectory_NotExists;
// case gbFileError_Permission: return ReadDirectory_Permission; // case gbFileError_Permission: return ReadDirectory_Permission;
} }
} }
if (!path_is_directory(path)) { if (!path_is_directory(path)) {
return ReadDirectory_NotDir; return ReadDirectory_NotDir;
} }
gbAllocator a = heap_allocator(); gbAllocator a = heap_allocator();
char *new_path = gb_alloc_array(a, char, path.len+3); char *new_path = gb_alloc_array(a, char, path.len+3);
defer (gb_free(a, new_path)); defer (gb_free(a, new_path));
gb_memmove(new_path, path.text, path.len); gb_memmove(new_path, path.text, path.len);
gb_memmove(new_path+path.len, "/*", 2); gb_memmove(new_path+path.len, "/*", 2);
new_path[path.len+2] = 0; new_path[path.len+2] = 0;
String np = make_string(cast(u8 *)new_path, path.len+2); String np = make_string(cast(u8 *)new_path, path.len+2);
String16 wstr = string_to_string16(a, np); String16 wstr = string_to_string16(a, np);
defer (gb_free(a, wstr.text)); defer (gb_free(a, wstr.text));
WIN32_FIND_DATAW file_data = {}; WIN32_FIND_DATAW file_data = {};
HANDLE find_file = FindFirstFileW(wstr.text, &file_data); HANDLE find_file = FindFirstFileW(wstr.text, &file_data);
if (find_file == INVALID_HANDLE_VALUE) { if (find_file == INVALID_HANDLE_VALUE) {
return ReadDirectory_Unknown; return ReadDirectory_Unknown;
} }
defer (FindClose(find_file)); defer (FindClose(find_file));
array_init(fi, a, 0, 100); array_init(fi, a, 0, 100);
do { do {
wchar_t *filename_w = file_data.cFileName; wchar_t *filename_w = file_data.cFileName;
u64 size = cast(u64)file_data.nFileSizeLow; u64 size = cast(u64)file_data.nFileSizeLow;
size |= (cast(u64)file_data.nFileSizeHigh) << 32; size |= (cast(u64)file_data.nFileSizeHigh) << 32;
String name = string16_to_string(a, make_string16_c(filename_w)); String name = string16_to_string(a, make_string16_c(filename_w));
if (name == "." || name == "..") { if (name == "." || name == "..") {
gb_free(a, name.text); gb_free(a, name.text);
continue; continue;
} }
String filepath = {}; String filepath = {};
filepath.len = path.len+1+name.len; filepath.len = path.len+1+name.len;
filepath.text = gb_alloc_array(a, u8, filepath.len+1); filepath.text = gb_alloc_array(a, u8, filepath.len+1);
defer (gb_free(a, filepath.text)); defer (gb_free(a, filepath.text));
gb_memmove(filepath.text, path.text, path.len); gb_memmove(filepath.text, path.text, path.len);
gb_memmove(filepath.text+path.len, "/", 1); gb_memmove(filepath.text+path.len, "/", 1);
gb_memmove(filepath.text+path.len+1, name.text, name.len); gb_memmove(filepath.text+path.len+1, name.text, name.len);
FileInfo info = {}; FileInfo info = {};
info.name = name; info.name = name;
info.fullpath = path_to_full_path(a, filepath); info.fullpath = path_to_full_path(a, filepath);
info.size = cast(i64)size; info.size = cast(i64)size;
info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
array_add(fi, info); array_add(fi, info);
} while (FindNextFileW(find_file, &file_data)); } while (FindNextFileW(find_file, &file_data));
if (fi->count == 0) { if (fi->count == 0) {
return ReadDirectory_Empty; return ReadDirectory_Empty;
} }
return ReadDirectory_None; return ReadDirectory_None;
} }
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) #elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) || defined(GB_SYSTEM_HAIKU)
#include <dirent.h> #include <dirent.h>
gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) { gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
GB_ASSERT(fi != nullptr); GB_ASSERT(fi != nullptr);
gbAllocator a = heap_allocator(); gbAllocator a = heap_allocator();
char *c_path = alloc_cstring(a, path); char *c_path = alloc_cstring(a, path);
defer (gb_free(a, c_path)); defer (gb_free(a, c_path));
DIR *dir = opendir(c_path); DIR *dir = opendir(c_path);
if (!dir) { if (!dir) {
switch (errno) { switch (errno) {
case ENOENT: case ENOENT:
return ReadDirectory_NotExists; return ReadDirectory_NotExists;
case EACCES: case EACCES:
return ReadDirectory_Permission; return ReadDirectory_Permission;
case ENOTDIR: case ENOTDIR:
return ReadDirectory_NotDir; return ReadDirectory_NotDir;
default: default:
// ENOMEM: out of memory // ENOMEM: out of memory
// EMFILE: per-process limit on open fds reached // EMFILE: per-process limit on open fds reached
// ENFILE: system-wide limit on total open files reached // ENFILE: system-wide limit on total open files reached
return ReadDirectory_Unknown; return ReadDirectory_Unknown;
} }
GB_PANIC("unreachable"); GB_PANIC("unreachable");
} }
array_init(fi, a, 0, 100); array_init(fi, a, 0, 100);
for (;;) { for (;;) {
struct dirent *entry = readdir(dir); struct dirent *entry = readdir(dir);
if (entry == nullptr) { if (entry == nullptr) {
break; break;
} }
String name = make_string_c(entry->d_name); String name = make_string_c(entry->d_name);
if (name == "." || name == "..") { if (name == "." || name == "..") {
continue; continue;
} }
String filepath = {}; String filepath = {};
filepath.len = path.len+1+name.len; filepath.len = path.len+1+name.len;
filepath.text = gb_alloc_array(a, u8, filepath.len+1); filepath.text = gb_alloc_array(a, u8, filepath.len+1);
defer (gb_free(a, filepath.text)); defer (gb_free(a, filepath.text));
gb_memmove(filepath.text, path.text, path.len); gb_memmove(filepath.text, path.text, path.len);
gb_memmove(filepath.text+path.len, "/", 1); gb_memmove(filepath.text+path.len, "/", 1);
gb_memmove(filepath.text+path.len+1, name.text, name.len); gb_memmove(filepath.text+path.len+1, name.text, name.len);
filepath.text[filepath.len] = 0; filepath.text[filepath.len] = 0;
struct stat dir_stat = {}; struct stat dir_stat = {};
if (stat((char *)filepath.text, &dir_stat)) { if (stat((char *)filepath.text, &dir_stat)) {
continue; continue;
} }
if (S_ISDIR(dir_stat.st_mode)) { if (S_ISDIR(dir_stat.st_mode)) {
continue; continue;
} }
i64 size = dir_stat.st_size; i64 size = dir_stat.st_size;
FileInfo info = {}; FileInfo info = {};
info.name = name; info.name = name;
info.fullpath = path_to_full_path(a, filepath); info.fullpath = path_to_full_path(a, filepath);
info.size = size; info.size = size;
array_add(fi, info); array_add(fi, info);
} }
if (fi->count == 0) { if (fi->count == 0) {
return ReadDirectory_Empty; return ReadDirectory_Empty;
} }
return ReadDirectory_None; return ReadDirectory_None;
} }
#else #else
#error Implement read_directory #error Implement read_directory
#endif #endif
#if !defined(GB_SYSTEM_WINDOWS) #if !defined(GB_SYSTEM_WINDOWS)
gb_internal bool write_directory(String path) { gb_internal bool write_directory(String path) {
char const *pathname = (char *) path.text; char const *pathname = (char *) path.text;
if (access(pathname, W_OK) < 0) { if (access(pathname, W_OK) < 0) {
return false; return false;
} }
return true; return true;
} }
#else #else
gb_internal bool write_directory(String path) { gb_internal bool write_directory(String path) {
String16 wstr = string_to_string16(heap_allocator(), path); String16 wstr = string_to_string16(heap_allocator(), path);
LPCWSTR wdirectory_name = wstr.text; LPCWSTR wdirectory_name = wstr.text;
HANDLE directory = CreateFileW(wdirectory_name, HANDLE directory = CreateFileW(wdirectory_name,
GENERIC_WRITE, GENERIC_WRITE,
0, 0,
NULL, NULL,
OPEN_EXISTING, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_BACKUP_SEMANTICS,
NULL); NULL);
if (directory == INVALID_HANDLE_VALUE) { if (directory == INVALID_HANDLE_VALUE) {
DWORD error_code = GetLastError(); DWORD error_code = GetLastError();
if (error_code == ERROR_ACCESS_DENIED) { if (error_code == ERROR_ACCESS_DENIED) {
return false; return false;
} }
} }
CloseHandle(directory); CloseHandle(directory);
return true; return true;
} }
#endif #endif
+46 -1
View File
@@ -831,8 +831,53 @@ gb_internal void futex_wait(Futex *f, Footex val) {
WaitOnAddress(f, (void *)&val, sizeof(val), INFINITE); WaitOnAddress(f, (void *)&val, sizeof(val), INFINITE);
} while (f->load() == val); } while (f->load() == val);
} }
#elif defined(GB_SYSTEM_HAIKU)
#include <pthread.h>
#include <unordered_map>
#include <memory>
struct MutexCond {
pthread_mutex_t mutex;
pthread_cond_t cond;
};
std::unordered_map<Futex*, std::unique_ptr<MutexCond>> futex_map;
MutexCond* get_mutex_cond(Futex* f) {
if (futex_map.find(f) == futex_map.end()) {
futex_map[f] = std::make_unique<MutexCond>();
pthread_mutex_init(&futex_map[f]->mutex, NULL);
pthread_cond_init(&futex_map[f]->cond, NULL);
}
return futex_map[f].get();
}
void futex_signal(Futex *f) {
MutexCond* mc = get_mutex_cond(f);
pthread_mutex_lock(&mc->mutex);
pthread_cond_signal(&mc->cond);
pthread_mutex_unlock(&mc->mutex);
}
void futex_broadcast(Futex *f) {
MutexCond* mc = get_mutex_cond(f);
pthread_mutex_lock(&mc->mutex);
pthread_cond_broadcast(&mc->cond);
pthread_mutex_unlock(&mc->mutex);
}
void futex_wait(Futex *f, Footex val) {
MutexCond* mc = get_mutex_cond(f);
pthread_mutex_lock(&mc->mutex);
while (f->load() == val) {
pthread_cond_wait(&mc->cond, &mc->mutex);
}
pthread_mutex_unlock(&mc->mutex);
}
#endif #endif
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
#pragma warning(pop) #pragma warning(pop)
#endif #endif