commit bd6b519d8af036db3bcc99339f81f9c182d687a3
parent eeba24b701e28010b4ada79cffd9625f157ab063
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 31 Jan 2021 12:47:57 -0500
os: add fdstream, stdfd
Diffstat:
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;