hare

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

commit 1775202449eec49bbd5cdc0f63c06b811271bedb
parent 2365ddceeb4688826c6bdef3986c22d23112fdb7
Author: Lorenz (xha) <me@xha.li>
Date:   Sat, 25 Nov 2023 15:18:07 +0100

OpenBSD: add io

Signed-off-by: Lorenz (xha) <me@xha.li>

Diffstat:
Aio/+openbsd/dup.ha | 45+++++++++++++++++++++++++++++++++++++++++++++
Aio/+openbsd/mmap.ha | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Aio/+openbsd/platform_file.ha | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aio/+openbsd/vector.ha | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mio/file.ha | 4++--
5 files changed, 232 insertions(+), 2 deletions(-)

diff --git a/io/+openbsd/dup.ha b/io/+openbsd/dup.ha @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use rt; + +// Flags for [[dup]] and [[dup2]] operations. +export type dupflag = enum { + NONE = 0, + + // Causes [[dup]] and [[dup2]] not to set the CLOEXEC flag on the + // duplicated file descriptor. By default, CLOEXEC is set. + NOCLOEXEC = rt::FD_CLOEXEC, +}; + +// Duplicates a file descriptor. +export fn dup(old: file, flags: dupflag) (file | error) = { + flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC + + match (rt::dup2(old, -1)) { + case let fd: int => + const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; + rt::fcntl(fd, rt::F_SETFD, fl | rt::FD_CLOEXEC)!; + return fd; + case let e: rt::errno => + return errors::errno(e); + }; +}; + +// Duplicates a file descriptor and stores the new file at a specific file +// descriptor number. If the file indicated by "new" already refers to an open +// file, this file will be closed before the file descriptor is reused. +export fn dup2(old: file, new: file, flags: dupflag) (file | error) = { + flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC + + match (rt::dup2(old, new)) { + case let fd: int => + const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; + rt::fcntl(fd, rt::F_SETFD, fl | flags)!; + return fd; + case let e: rt::errno => + return errors::errno(e); + }; +}; +\ No newline at end of file diff --git a/io/+openbsd/mmap.ha b/io/+openbsd/mmap.ha @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use rt; + +// Values for the [[mmap]] prot parameter. Only the EXEC, READ, WRITE, and NONE +// values are portable. +export type prot = enum int { + NONE = rt::PROT_NONE, + READ = rt::PROT_READ, + WRITE = rt::PROT_WRITE, + EXEC = rt::PROT_EXEC, +}; + +// Values for the [[mmap]] flags parameter. Only the SHARED, PRIVATE, and FIXED +// values are portable. +export type mflag = enum int { + SHARED = rt::MAP_SHARED, + PRIVATE = rt::MAP_PRIVATE, + FIXED = rt::MAP_FIXED, + ANON = rt::MAP_ANON, + STACK = rt::MAP_STACK, + CONCEAL = rt::MAP_CONCEAL +}; + +// Performs the mmap syscall. Consult your system for documentation on this +// function. +export fn mmap( + addr: nullable *opaque, + length: size, + prot: prot, + flags: mflag, + fd: file, + offs: size +) (*opaque | errors::error) = { + match (rt::mmap(addr, length, prot, flags, fd, offs: i64)) { + case let ptr: *opaque => + return ptr; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Unmaps memory previously mapped with [[mmap]]. +export fn munmap(addr: *opaque, length: size) (void | errors::error) = { + match (rt::munmap(addr, length)) { + case void => + return; + case let err: rt::errno => + return errors::errno(err); + }; +}; diff --git a/io/+openbsd/platform_file.ha b/io/+openbsd/platform_file.ha @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use rt; + +// This is an opaque type which encloses an OS-level file handle resource. It +// can be used as a [[handle]] in most situations, but there are some APIs which +// require a [[file]] with some OS-level handle backing it - this type is used +// for such APIs. +// +// On OpenBSD, [[file]] is a file descriptor. +export type file = int; + +// Opens a Unix file descriptor as a file. This is a low-level interface, to +// open files most programs will use something like [[os::open]]. This function +// is not portable. +export fn fdopen(fd: int) file = fd; + +fn fd_read(fd: file, buf: []u8) (size | EOF | error) = { + match (rt::read(fd, buf: *[*]u8, len(buf))) { + case let err: rt::errno => + return errors::errno(err); + case let n: size => + switch (n) { + case 0 => + return EOF; + case => + return n; + }; + }; +}; + +fn fd_write(fd: file, buf: const []u8) (size | error) = { + match (rt::write(fd, buf: *const [*]u8, len(buf))) { + case let err: rt::errno => + return errors::errno(err); + case let n: size => + return n; + }; +}; + +fn fd_close(fd: file) (void | error) = { + match (rt::close(fd)) { + case void => void; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +fn fd_seek( + fd: file, + offs: off, + whence: whence, +) (off | error) = { + match (rt::lseek(fd, offs: i64, whence: int)) { + case let err: rt::errno => + return errors::errno(err); + case let n: i64 => + return n: off; + }; +}; + +fn fd_copy(to: file, from: file) (size | error) = errors::unsupported; + +fn fd_lock(fd: file, flags: int) (bool | error) = { + match (rt::flock(fd: int, flags)) { + case void => return true; + case let e: rt::errno => + if (e == rt::EWOULDBLOCK: rt::errno) { + return false; + } else { + return errors::errno(e); + }; + }; +}; + +fn fd_trunc(fd: file, ln: size) (void | error) = { + match (rt::ftruncate(fd: int, ln: rt::off_t)) { + case void => void; + case let e: rt::errno => return errors::errno(e); + }; +}; diff --git a/io/+openbsd/vector.ha b/io/+openbsd/vector.ha @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use rt; +use types; + +export type vector = rt::iovec; + +// Creates a vector for use with [[writev]] and [[readv]]. +export fn mkvector(buf: []u8) vector = vector { + iov_base = buf: *[*]u8, + iov_len = len(buf), +}; + +// Performs a vectored read on the given file. A read is performed on each of +// the vectors, prepared with [[mkvector]], in order, and the total number of +// bytes read is returned. +export fn readv(fd: file, vectors: vector...) (size | EOF | error) = { + if (len(vectors) > types::INT_MAX: size) { + return errors::invalid; + }; + match (rt::readv(fd, vectors: *[*]rt::iovec, len(vectors): int)) { + case let err: rt::errno => + return errors::errno(err); + case let n: size => + switch (n) { + case 0 => + return EOF; + case => + return n; + }; + }; +}; + +// Performs a vectored write on the given file. Each of the vectors, prepared +// with [[mkvector]], are written to the file in order, and the total number of +// bytes written is returned. +export fn writev(fd: file, vectors: vector...) (size | error) = { + if (len(vectors) > types::INT_MAX: size) { + return errors::invalid; + }; + match (rt::writev(fd, vectors: *[*]rt::iovec, len(vectors): int)) { + case let err: rt::errno => + return errors::errno(err); + case let n: size => + return n; + }; +}; diff --git a/io/file.ha b/io/file.ha @@ -13,8 +13,8 @@ export type lockop = enum int { UNLOCK = rt::LOCK_UN, }; -// Apply or remove an advisory lock on an open file. If block is true, the request will block while waiting -// for the lock. +// Apply or remove an advisory lock on an open file. If block is true, the +// request will block while waiting for the lock. export fn lock(fd: file, block: bool, op: lockop) (bool | error) = { let flags = op: int; if (!block) flags |= rt::LOCK_NB;