hare

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

commit bd6b519d8af036db3bcc99339f81f9c182d687a3
parent eeba24b701e28010b4ada79cffd9625f157ab063
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun, 31 Jan 2021 12:47:57 -0500

os: add fdstream, stdfd

Diffstat:
Mos/+linux/environ.ha | 4++--
Aos/+linux/errors.ha | 14++++++++++++++
Aos/+linux/fdstream.ha | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aos/+linux/stdfd.ha | 7+++++++
Aos/stdfd.ha | 10++++++++++
5 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/os/+linux/environ.ha b/os/+linux/environ.ha @@ -11,7 +11,7 @@ export let args: []str = []; // syscall if we don't need it. let args_static: [32]str = [""...]; -@init fn init() void = { +@init fn init_environ() void = { if (rt::argc < len(args_static)) { args = args_static[..rt::argc]; } else { @@ -24,7 +24,7 @@ let args_static: [32]str = [""...]; }; }; -@fini fn fini() void = { +@fini fn fini_environ() void = { if (rt::argc >= len(args_static)) { free(args); }; diff --git a/os/+linux/errors.ha b/os/+linux/errors.ha @@ -0,0 +1,14 @@ +use io; + +fn io_errstr(data: *void) str = { + return "TODO: insert errno description here"; +}; + +// TODO: Implement the inverse of this and make it public +fn errno_to_io(err: rt::errno) io::error = { + let e: io::os_error = struct { + string: *fn(data: *void) str = &io_errstr, + data: *void = err: uintptr: *void, + }; + return e: io::error; +}; diff --git a/os/+linux/fdstream.ha b/os/+linux/fdstream.ha @@ -0,0 +1,57 @@ +use io; +use rt; + +type fd_stream = struct { + stream: io::stream, + fd: int, +}; + +fn fd_read(s: *io::stream, buf: []u8) (size | io::error) = { + let stream = s: *fd_stream; + let r = rt::read(stream.fd, (&buf: *types::slice).data: *[*]u8, len(buf)); + return match (rt::wrap_return(r)) { + err: rt::errno => errno_to_io(err), + n: size => { + switch (n) { + 0z => io::closed: io::error, + * => n, + }; + }, + }; +}; + +fn fd_write(s: *io::stream, buf: const []u8) (size | io::error) = { + let stream = s: *fd_stream; + let r = rt::write(stream.fd, + (&buf: *types::slice).data: *const [*]u8, len(buf)); + return match (rt::wrap_return(r)) { + err: rt::errno => errno_to_io(err), + n: size => n, + }; +}; + +fn fd_close(s: *io::stream) void = { + let stream = s: *fd_stream; + rt::close(stream.fd); + free(stream); +}; + +// Opens a Unix file descriptor as an io::stream. If 'name' is an empty string, +// a name will be generated based on the file descriptor number. +export fn fdopen(fd: int, name: str) *io::stream = { + // TODO: strings::dup the name, and if empty, generate a name from the + // file descriptor number. + // + // Also TODO: consider making the caller specify what subset of + // operations should be supported + let stream = alloc(*fd_stream, struct { + stream: io::stream = struct { + name: str = name, + reader: nullable *io::reader = &fd_read, + writer: nullable *io::writer = &fd_write, + closer: nullable *io::closer = &fd_close, + }, + fd: int = fd, + }); + return &stream.stream; +}; diff --git a/os/+linux/stdfd.ha b/os/+linux/stdfd.ha @@ -0,0 +1,7 @@ +use io; + +@init fn init_stdfd() void = { + stdin = fdopen(0, "<stdin>"); + stdout = fdopen(1, "<stdout>"); + stderr = fdopen(2, "<stderr>"); +}; diff --git a/os/stdfd.ha b/os/stdfd.ha @@ -0,0 +1,10 @@ +use io; + +// The standard input. +export let stdin: *io::stream = null: *io::stream; + +// The standard output. +export let stdout: *io::stream = null: *io::stream; + +// The standard error. +export let stderr: *io::stream = null: *io::stream;