hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit a8d004bdfc29e49420d42fd873669e2f53a3e9ec
parent f0e41c90d0d19f77603d44c4e51dbe3554d6ac82
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed, 24 Feb 2021 09:20:53 -0500

os: refine the open & create APIs

Diffstat:
Mio/types.ha | 11+++++++----
Mos/+linux/fdstream.ha | 4++--
Mos/+linux/open.ha | 75++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mos/+linux/stdfd.ha | 6+++---
Mrt/+linux/types.ha | 21+++++++++++++++++----
5 files changed, 91 insertions(+), 26 deletions(-)

diff --git a/io/types.ha b/io/types.ha @@ -25,12 +25,15 @@ export fn errstr(err: error) str = { }; }; -export type mode = enum uint { - RDONLY = 0, - WRONLY = 1, - RDWR = 2, +// Used to indicate if a stream should be used for reading, or writing, or both. +export type mode = enum u8 { + NONE = 0, + READ = 1 << 0, + WRITE = 1 << 1, + RDWR = READ | WRITE, }; +// From "whence" a seek operation should occur. export type whence = enum { SET = 0, CUR = 1, diff --git a/os/+linux/fdstream.ha b/os/+linux/fdstream.ha @@ -20,10 +20,10 @@ fn static_fdopen( }, fd = fd, }; - if (mode == io::mode::RDONLY || mode == io::mode::RDWR) { + if (mode & io::mode::READ == io::mode::READ) { stream.stream.reader = &fd_read; }; - if (mode == io::mode::WRONLY || mode == io::mode::RDWR) { + if (mode & io::mode::WRITE == io::mode::WRITE) { stream.stream.writer = &fd_write; }; return &stream.stream; diff --git a/os/+linux/open.ha b/os/+linux/open.ha @@ -2,8 +2,12 @@ use io; use rt; use strings; -export type flags = enum { - NONE = 0, +// Flags to use for opening a file. Not all operating systems support all flags; +// at a minimum, RDONLY, WRONLY, RDWR, and CREATE will be supported. +export type flags = enum int { + RDONLY = 0, + WRONLY = 1, + RDWR = 2, CREATE = 0o100, EXCLUSIVE = 0o200, NOCTTY = 0o400, @@ -20,17 +24,52 @@ export type flags = enum { // Opens a file from the filesystem. // -// If no flags are provided, the default is NOCTTY | CLOEXEC. +// If no flags are provided, the default for +linux is RDONLY | NOCTTY | CLOEXEC. export fn open( path: (str | []u8), - mode: io::mode, flag: flags... ) (*io::stream | io::error) = { - // Verify that these line up with the Linux ABI: - static assert(io::mode::RDONLY: int == rt::O_RDONLY); - static assert(io::mode::WRONLY: int == rt::O_WRONLY); - static assert(io::mode::RDWR: int == rt::O_RDWR); + const p: []u8 = match (path) { + s: str => strings::to_utf8(s), + b: []u8 => b, + }; + const name: str = match (path) { + s: str => s, + b: []u8 => "<open([]u8)>", + }; + + let oflags = 0; + let iomode = io::mode::NONE; + if (len(flag) == 0z) { + oflags |= (flags::NOCTTY | flags::CLOEXEC | flags::RDONLY): int; + }; + for (let i = 0z; i < len(flag); i += 1z) { + oflags |= flag[i]: int; + }; + if (oflags: flags & flags::RDWR == flags::RDWR) { + iomode = io::mode::RDWR; + } else if (oflags: flags & flags::RDONLY == flags::RDONLY) { + iomode = io::mode::READ; + } else if (oflags: flags & flags::RDONLY == flags::RDONLY) { + iomode = io::mode::WRITE; + }; + + let fd: int = match (rt::open(p: *[*]u8: *const char, oflags, 0u)) { + err: rt::errno => return errno_to_io(err), + n: int => n, + }; + + return fdopen(fd, name, iomode); +}; + +// Equivalent to [open], but allows the caller to specify a file mode for the +// new file. If no other flag is given, the default read/write mode is WRONLY. +export fn create( + path: (str | []u8), + mode: uint, + flag: flags... +) (*io::stream | io::error) = { const p: []u8 = match (path) { s: str => strings::to_utf8(s), b: []u8 => b, @@ -40,18 +79,28 @@ export fn open( b: []u8 => "<open([]u8)>", }; - let m = mode: int; + let oflags = 0; + let iomode = io::mode::NONE; if (len(flag) == 0z) { - m |= flags::NOCTTY: int | flags::CLOEXEC: int; + oflags |= (flags::NOCTTY | flags::CLOEXEC | flags::WRONLY): int; }; for (let i = 0z; i < len(flag); i += 1z) { - m |= flag[i]: int; + oflags |= flag[i]: int; + }; + oflags |= flags::CREATE: int; + + if (oflags: flags & flags::RDWR == flags::RDWR) { + iomode = io::mode::RDWR; + } else if (oflags: flags & flags::RDONLY == flags::RDONLY) { + iomode = io::mode::READ; + } else if (oflags: flags & flags::RDONLY == flags::RDONLY) { + iomode = io::mode::WRITE; }; - let fd: int = match (rt::open(p: *[*]u8: *const char, m, 0u)) { + let fd: int = match (rt::open(p: *[*]u8: *const char, oflags, mode)) { err: rt::errno => return errno_to_io(err), n: int => n, }; - return fdopen(fd, name, mode); + return fdopen(fd, name, iomode); }; diff --git a/os/+linux/stdfd.ha b/os/+linux/stdfd.ha @@ -5,7 +5,7 @@ let static_stdout: fd_stream = fd_stream { ... }; let static_stderr: fd_stream = fd_stream { ... }; @init fn init_stdfd() void = { - stdin = static_fdopen(0, "<stdin>", io::mode::RDONLY, &static_stdin); - stdout = static_fdopen(1, "<stdout>", io::mode::WRONLY, &static_stdout); - stderr = static_fdopen(2, "<stderr>", io::mode::WRONLY, &static_stderr); + stdin = static_fdopen(0, "<stdin>", io::mode::READ, &static_stdin); + stdout = static_fdopen(1, "<stdout>", io::mode::WRITE, &static_stdout); + stderr = static_fdopen(2, "<stderr>", io::mode::WRITE, &static_stderr); }; diff --git a/rt/+linux/types.ha b/rt/+linux/types.ha @@ -30,11 +30,24 @@ export def AT_STATX_FORCE_SYNC: int = 0x2000; export def AT_STATX_DONT_SYNC: int = 0x4000; export def AT_RECURSIVE: int = 0x8000; -export def O_RDONLY: int = 0; -export def O_WRONLY: int = 1; -export def O_RDWR: int = 2; -// TODO: Add the other flags: +export def O_RDONLY: int = 0o0; +export def O_WRONLY: int = 0o1; +export def O_RDWR: int = 0o2; +export def O_CREATE: int = 0o100; +export def O_EXCLUSIVE: int = 0o200; +export def O_NOCTTY: int = 0o400; +export def O_TRUNC: int = 0o1000; +export def O_APPEND: int = 0o2000; +export def O_NONBLOCK: int = 0o4000; +export def O_DSYNC: int = 0o10000; +export def O_SYNC: int = 0o4010000; +export def O_RSYNC: int = 0o4010000; +export def O_DIRECTORY: int = 0o200000; +export def O_NOFOLLOW: int = 0o400000; +export def O_NOATIME: int = 0o1000000; export def O_CLOEXEC: int = 0o2000000; +export def O_PATH: int = 0o10000000; +export def O_TMPFILE: int = 0o20000000; type statx_timestamp = struct { tv_sec: i64,