- Added path::home_directory, path::documents_directory, path::videos_directory, path::pictures_directory, path::desktop_directory, path::screenshots_directory,

`path::public_share_directory`, `path::templates_directory`, `path::saved_games_directory`, `path::music_directory`, `path::downloads_directory`.
  Fix codegen bug in expressions like `foo(x()) ?? io::EOF?` causing irregular crashes.
This commit is contained in:
Christoffer Lerno
2025-09-04 21:34:34 +02:00
committed by Christoffer Lerno
parent cbd415881b
commit 69b3263a00
17 changed files with 342 additions and 42 deletions

View File

@@ -35,6 +35,7 @@ faultdef
NO_PERMISSION,
OUT_OF_SPACE,
OVERFLOW,
PATH_COULD_NOT_BE_FOUND,
READ_ONLY,
SYMLINK_FAILED,
TOO_MANY_DESCRIPTORS,

View File

@@ -1,5 +1,112 @@
module std::io::os;
enum NativeSystemDir
{
DESKTOP,
DOCUMENTS,
VIDEOS,
MUSIC,
DOWNLOADS,
PICTURES,
TEMPLATES,
PUBLIC_SHARE,
SAVED_GAMES,
SCREENSHOTS
}
module std::io::os @if(env::LIBC);
import std::io::path, std::os;
import std::io, std::os;
fn String? win32_get_known_folder_temp(Win32_REFKNOWNFOLDERID rfid) @private @if(env::WIN32)
{
Win32_PWSTR path;
Win32_HRESULT res = win32::shGetKnownFolderPath(rfid, 0x00008000 /* KF_FLAG_CREATE */, null, &path);
if (res) return io::PATH_COULD_NOT_BE_FOUND?;
return string::from_wstring(tmem, (WString)path);
}
fn Path? native_home_directory(Allocator allocator) => @pool()
{
$switch env::OS_TYPE:
$case IOS:
$case MACOS:
$case TVOS:
$case WATCHOS:
$case FREEBSD:
$case KFREEBSD:
$case LINUX:
$case NETBSD:
$case OPENBSD:
$case HAIKU:
return path::new(allocator, env::tget_var("HOME")) ?? io::PATH_COULD_NOT_BE_FOUND?;
$case WIN32:
return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_PROFILE));
$default:
return io::PATH_COULD_NOT_BE_FOUND?;
$endswitch
}
fn Path? native_user_directory(Allocator allocator, NativeSystemDir dir) => @pool()
{
$switch env::OS_TYPE:
$case FREEBSD:
$case KFREEBSD:
$case LINUX:
$case NETBSD:
$case OPENBSD:
$case HAIKU:
switch (dir)
{
case DESKTOP: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "DESKTOP"));
case DOWNLOADS: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "DOWNLOAD"));
case DOCUMENTS: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "DOCUMENTS"));
case MUSIC: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "MUSIC"));
case VIDEOS: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "VIDEOS"));
case PICTURES: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "PICTURES"));
case PUBLIC_SHARE: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "PUBLICSHARE"));
case TEMPLATES: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "TEMPLATES"));
case SAVED_GAMES:
case SCREENSHOTS: nextcase;
default: return io::PATH_COULD_NOT_BE_FOUND?;
}
$case IOS:
$case MACOS:
$case WATCHOS:
$case TVOS:
switch (dir)
{
case DESKTOP: return path::new(allocator, darwin::find_first_directory_temp(DESKTOP, USER));
case DOWNLOADS: return path::new(allocator, darwin::find_first_directory_temp(DOWNLOADS, USER));
case DOCUMENTS: return path::new(allocator, darwin::find_first_directory_temp(DOCUMENT, USER));
case MUSIC: return path::new(allocator, darwin::find_first_directory_temp(MUSIC, USER));
case VIDEOS: return path::new(allocator, darwin::find_first_directory_temp(MOVIES, USER));
case PICTURES: return path::new(allocator, darwin::find_first_directory_temp(PICTURES, USER));
case PUBLIC_SHARE: return path::new(allocator, darwin::find_first_directory_temp(SHARED_PUBLIC, USER));
case SAVED_GAMES:
case SCREENSHOTS:
case TEMPLATES: nextcase;
default: return io::PATH_COULD_NOT_BE_FOUND?;
}
$case WIN32:
switch (dir)
{
case DOWNLOADS: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_DOWNLOADS));
case DOCUMENTS: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_DOCUMENTS));
case DESKTOP: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_DESKTOP));
case MUSIC: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_MUSIC));
case VIDEOS: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_VIDEOS));
case PICTURES: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_PICTURES));
case SAVED_GAMES: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_SAVED_GAMES));
case SCREENSHOTS: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_SCREENSHOTS));
case TEMPLATES: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_TEMPLATES));
case PUBLIC_SHARE: nextcase;
default: return io::PATH_COULD_NOT_BE_FOUND?;
}
$default:
return io::PATH_COULD_NOT_BE_FOUND?;
$endswitch
}
fn Path? native_temp_directory(Allocator allocator) @if(!env::WIN32)
{
@@ -23,7 +130,6 @@ fn Path? native_temp_directory(Allocator allocator) @if(env::WIN32) => @pool()
module std::io::os @if(env::NO_LIBC);
import std::io::path;
macro Path? native_temp_directory(Allocator allocator)
{
return io::UNSUPPORTED_OPERATION?;
}
macro Path? native_home_directory(Allocator allocator) => io::PATH_COULD_NOT_BE_FOUND?;
macro Path? native_temp_directory(Allocator allocator) => io::PATH_COULD_NOT_BE_FOUND?;
fn Path? native_user_directory(Allocator allocator, NativeSystemDir dir) => io::PATH_COULD_NOT_BE_FOUND?;

View File

@@ -57,6 +57,18 @@ macro void? chdir(path)
fn Path? temp_directory(Allocator allocator) => os::native_temp_directory(allocator);
fn Path? home_directory(Allocator allocator) => os::native_home_directory(allocator);
fn Path? desktop_directory(Allocator allocator) => os::native_user_directory(allocator, DESKTOP);
fn Path? videos_directory(Allocator allocator) => os::native_user_directory(allocator, VIDEOS);
fn Path? music_directory(Allocator allocator) => os::native_user_directory(allocator, MUSIC);
fn Path? documents_directory(Allocator allocator) => os::native_user_directory(allocator, DOCUMENTS);
fn Path? screenshots_directory(Allocator allocator) => os::native_user_directory(allocator, SCREENSHOTS);
fn Path? saved_games_directory(Allocator allocator) => os::native_user_directory(allocator, SAVED_GAMES);
fn Path? downloads_directory(Allocator allocator) => os::native_user_directory(allocator, DOWNLOADS);
fn Path? pictures_directory(Allocator allocator) => os::native_user_directory(allocator, PICTURES);
fn Path? templates_directory(Allocator allocator) => os::native_user_directory(allocator, TEMPLATES);
fn Path? public_share_directory(Allocator allocator) => os::native_user_directory(allocator, PUBLIC_SHARE);
fn void? delete(Path path) => os::native_remove(path.str_view()) @inline;
macro bool @is_pathlike(#path) @const => $typeof(#path) == String ||| $typeof(#path) == Path;

View File

@@ -1,11 +1,18 @@
module std::os::macos::cf @if(env::DARWIN) @link(env::DARWIN, "CoreFoundation.framework");
typedef CFArrayRef = void*;
typedef CFArray = inline CFType;
alias CFArrayRef = CFArray*;
typedef CFArrayCallBacksRef = void*;
typedef CFMutableArrayRef = void*;
typedef CFMutableArray = inline CFArray;
typedef CFMutableArrayRef = CFMutableArray*;
extern fn CFIndex CFArray.getCount(&self) @extern("CFArrayGetCount");
extern fn void* CFArray.getValueAtIndex(&self, CFIndex i) @extern("CFArrayGetValueAtIndex");
extern fn CFArrayRef macos_CFArrayCreate(CFAllocatorRef allocator, void** values, CFIndex num_values, CFArrayCallBacksRef callBacks) @extern("CFArrayCreate") @builtin;
extern fn CFArrayRef macos_CFArrayCopy(CFAllocatorRef allocator, CFArrayRef array) @extern("CFArrayCopy") @builtin;
extern fn CFIndex macos_CFArrayGetCount(CFArrayRef array) @extern("CFArrayGetCount") @builtin;
extern fn void macos_CFArrayAppendArray(CFMutableArrayRef theArray, CFArrayRef otherArray, CFRange otherRange) @extern("CFArrayAppendArray") @builtin;
extern fn void CFMutableArray.appendArray(&self, CFArrayRef otherArray, CFRange otherRange) @extern("CFArrayAppendArray");
extern fn void CFMutableArray.appendValue(&self, void *value) @extern("CFArrayAppendValue");
extern fn CFMutableArrayRef macos_CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, CFArrayCallBacksRef callBacks) @extern("CFArrayCreateMutable") @builtin;
extern fn void macos_CFArrayAppendValue(CFMutableArrayRef theArray, void *value) @extern("CFArrayAppendValue") @builtin;

View File

@@ -1,13 +1,42 @@
module std::os::macos::cf @if(env::DARWIN) @link(env::DARWIN, "CoreFoundation.framework");
typedef CFTypeRef = void*;
typedef CFType = void;
typedef CFTypeRef = CFType*;
alias CFIndex = isz;
typedef CFString = inline CFType;
alias CFStringRef = CFString*;
struct CFRange
{
CFIndex location;
CFIndex length;
}
extern fn CFTypeRef macos_CFRetain(CFTypeRef cf) @extern("CFRetain") @builtin;
extern fn void macos_CFRelease(CFTypeRef cf) @extern("CFRelease") @builtin;
extern fn ZString CFString.getCStringPtr(&self, CFStringEncoding encoding) @extern("CFStringGetCStringPtr");
extern fn ZString CFString.getCString(&self, char* buffer, usz len, CFStringEncoding encoding) @extern("CFStringGetCString");
extern fn CFTypeRef CFType.retain(&self) @extern("CFRetain");
extern fn void CFType.release(&self) @extern("CFRelease");
extern fn CFIndex CFType.getRetainCount(&self) @extern("CFGetRetainCount");
enum CFStringEncoding : const uint
{
INVALID_ID = 0xffffffffU,
MAC_ROMAN = 0,
WINDOWS_LATIN_1 = 0x0500,
ISO_LATIM_1 = 0x0201,
NEXT_STEP_LATIN = 0x0B01,
ASCII = 0x0600,
UNICODE = 0x0100,
UTF8 = 0x08000100,
NON_LOSSY_ASCII = 0x0BFF,
UTF16 = 0x0100,
UTF16BE = 0x10000100,
UTF16LE = 0x14000100,
UTF32 = 0x0c000100,
UTF32BE = 0x18000100,
UTF32LE = 0x1c000100
}

View File

@@ -1,2 +1,60 @@
module std::os::darwin @if(env::DARWIN);
module std::os::darwin @if(env::DARWIN) @link("Foundation.framework");
import std::os::macos::cf, std::os::macos::objc, std::io;
enum NSSearchPathDomainMask : const NSUInteger
{
USER = 1,
LOCAL = 2,
NETWORK = 4,
SYSTEM = 8,
ALL = 0x0ffff
}
enum NSSearchPathDirectory : const NSUInteger
{
APPLICATION = 1,
DEMO_APPLICATION,
DEVELOPER_APPLICATION,
ADMIN_APPLICATION,
LIBRARY,
DEVELOPER,
USER,
DOCUMENTATION,
DOCUMENT,
CORE_SERVICE,
AUTOSAVED_INFORMATION,
DESKTOP = 12,
CACHES = 13,
APPLICATION_SUPPORT = 14,
DOWNLOADS = 15,
INPUT_METHODS = 16,
MOVIES = 17,
MUSIC = 18,
PICTURES = 19,
PRINTER_DESCRIPTION = 20,
SHARED_PUBLIC = 21,
PREFERENCE_PANES = 22,
APPLICATION_SCRIPTS = 23,
ITEM_REPLACEMENT = 99,
ALL_APPLICATIONS = 100,
ALL_LIBRARIES = 101,
TRASH = 102,
}
// real signature in Foundation
extern fn CFArrayRef nsSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, bool expandTilde) @extern("NSSearchPathForDirectoriesInDomains");
fn String? find_first_directory_temp(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask)
{
objc::@autoreleasepool()
{
CFArrayRef arr = nsSearchPathForDirectoriesInDomains(directory, domainMask, true);
if (!arr.getCount()) return io::PATH_COULD_NOT_BE_FOUND?;
CFStringRef str = (CFStringRef)arr.getValueAtIndex(0);
char* buffer = tmalloc(2048);
if (!str.getCString(buffer, 2048, UTF8)) return io::PATH_COULD_NOT_BE_FOUND?;
return ((ZString)buffer).str_view();
};
}

View File

@@ -20,6 +20,9 @@ macro bool ObjcClass.equals(ObjcClass a, ObjcClass b) => a == b;
fn ObjcId alloc(ObjcClass cls) => objc::msg_send(cls, SendVoid, "alloc");
fn void release(ObjcId id) => objc::msg_send(id, SendVoid, "release");
alias NSUInteger = $typefrom(env::ARCH_64_BIT ??? ulong : uint);
alias NSInteger = $typefrom(env::ARCH_64_BIT ??? long : int);
macro ObjcClass? class_by_name(ZString c)
{
ObjcClass cls = objc::lookUpClass(c);
@@ -43,6 +46,15 @@ macro msg_send(id, $FunctionType, ZString $selector, ...)
return (($FunctionType)&msgSend)((ObjcId)id, sel_getUid($selector), $vasplat);
}
macro void @autoreleasepool(;@body())
{
void* ctx = objc_autoreleasePoolPush();
defer objc_autoreleasePoolPop(ctx);
@body();
}
extern fn void* objc_autoreleasePoolPush();
extern fn void objc_autoreleasePoolPop(void* context);
extern fn ObjcClass getClass(ZString name) @extern("objc_getClass");
extern fn int getClassList(ObjcClass* buffer, int buffer_count) @extern("objc_getClassList");
extern fn ObjcClass lookUpClass(ZString name) @extern("objc_lookUpClass") @builtin;

View File

@@ -0,0 +1,16 @@
module std::os::win32 @if(env::WIN32) @link("shell32");
typedef Win32_REFKNOWNFOLDERID = Win32_KNOWNFOLDERID*;
typedef Win32_KNOWNFOLDERID = Win32_GUID;
extern fn Win32_HRESULT shGetKnownFolderPath(Win32_REFKNOWNFOLDERID rfid, Win32_DWORD dwFlags, Win32_HANDLE hToken, Win32_PWSTR* ppszPath) @extern("SHGetKnownFolderPath");
const Win32_KNOWNFOLDERID FOLDERID_PROFILE = { 0x5E6C858F, 0x0E22, 0x4760, x"9AFEEA3317B67173" };
const Win32_KNOWNFOLDERID FOLDERID_DESKTOP = { 0xB4BFCC3A, 0xDB2C, 0x424C, x"B0297FE99A87C641" };
const Win32_KNOWNFOLDERID FOLDERID_DOCUMENTS = { 0xFDD39AD0, 0x238F, 0x46AF, x"ADB46C85480369C7" };
const Win32_KNOWNFOLDERID FOLDERID_DOWNLOADS = { 0x374de290, 0x123f, 0x4565, x"916439c4925e467b" };
const Win32_KNOWNFOLDERID FOLDERID_MUSIC = { 0x4BD8D571, 0x6D19, 0x48D3, x"BE97422220080E43" };
const Win32_KNOWNFOLDERID FOLDERID_PICTURES = { 0x33E28130, 0x4E1E, 0x4676, x"835A98395C3BC3BB" };
const Win32_KNOWNFOLDERID FOLDERID_SAVED_GAMES = { 0x4c5c32ff, 0xbb9d, 0x43b0, x"b5b42d72e54eaaa4" };
const Win32_KNOWNFOLDERID FOLDERID_SCREENSHOTS = { 0xb7bede81, 0xdf94, 0x4682, x"a7d857a52620b86f" };
const Win32_KNOWNFOLDERID FOLDERID_TEMPLATES = { 0xA63293E8, 0x664E, 0x48DB, x"A079DF759E0509F7" };
const Win32_KNOWNFOLDERID FOLDERID_VIDEOS = { 0x18989B1D, 0x99B5, 0x455B, x"841CAB7C74E4DDFC" };

53
lib/std/os/xdg.c3 Normal file
View File

@@ -0,0 +1,53 @@
module std::os::posix @if(env::POSIX);
import std::io, std::os::env;
fn String? xdg_user_dir_lookup(Allocator allocator, String type) => @pool()
{
String home = env::tget_var("HOME")!;
String config_file @noinit;
if (try String config_home = env::tget_var("XDG_CONFIG_HOME") && config_home.len)
{
config_file = config_home.tconcat("/user-dirs.dirs");
}
else
{
config_file = home.tconcat("/.config/user-dirs.dirs");
}
File f = file::open(config_file, "r")!;
defer (void)f.close();
while (try line = io::treadline(&f))
{
line = line.trim();
if (!line.starts_with("XDG_")) continue;
line = line[4..];
if (!line.starts_with(type)) continue;
line = line[type.len ..];
if (!line.starts_with("_DIR")) continue;
line = line[4..];
line = line.trim();
if (!line.starts_with("=")) continue;
line = line[1..].trim();
if (!line.starts_with("\"")) continue;
line = line[1..];
bool relative = false;
if (line.starts_with("$HOME/"))
{
relative = true;
line = line[6..];
}
else
{
if (!line.starts_with("/")) continue;
if (line.len < 2) continue;
line = line[1..];
}
if (line.len < 1 || line[^1] != '"') continue;
line = line[:^1];
if (relative)
{
return string::format(allocator, "%s/%s", home, line);
}
return line.copy(allocator);
}
return io::PATH_COULD_NOT_BE_FOUND?;
}