commit 904ef3090352080cee6f7a0898cbf32066d3f536
parent 098879d7cd61043130abc1125ec63a1b564e9e31
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 4 Sep 2021 10:51:50 +0200
io: introduce io::unwrapfd
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
3 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/io/+linux/file.ha b/io/+linux/file.ha
@@ -48,16 +48,20 @@ export fn is_file(s: *stream) bool = {
|| s.copier == &fd_copy;
};
-// Returns the file descriptor for a given [[file]] or [[stream]]. In the latter
-// case, a non-file input will cause the program to abort. This function is not
+// Returns the file descriptor for a given [[file]]. This function is not
// portable.
-export fn fd(f: (*file | *stream)) int = match (f) {
- f: *file => f.fd,
- f: *stream => {
- assert(is_file(f));
- let f = f: *file;
- yield f.fd;
- },
+export fn fd(f: *file) int = f.fd;
+
+// Returns the file descriptor for a given [[stream]], returning void if the
+// stream is not backed by a file. This function is not portable.
+export fn unwrapfd(s: *stream) (int | void) = {
+ for (!is_file(s)) {
+ s = match (io::source(s)) {
+ errors::unsupported => return,
+ s: *io::stream => s,
+ };
+ };
+ return fd(s: *file);
};
fn fd_read(s: *stream, buf: []u8) (size | EOF | error) = {
diff --git a/unix/tty/+linux/isatty.ha b/unix/tty/+linux/isatty.ha
@@ -4,7 +4,10 @@ use os;
// Returns whether the given stream is connected to a terminal.
export fn isatty(stream: *io::stream) bool = {
- let fd = io::fd(stream);
+ let fd = match (io::unwrapfd(stream)) {
+ void => return false,
+ fd: int => fd,
+ };
let wsz = rt::winsize { ... };
return match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *void)) {
e: rt::errno => false,
diff --git a/unix/tty/+linux/winsize.ha b/unix/tty/+linux/winsize.ha
@@ -5,7 +5,10 @@ use rt;
// Returns the dimensions of underlying terminal of the stream.
export fn winsize(tty: *io::stream) (ttysize | error) = {
- let fd = io::fd(tty);
+ let fd = match (io::unwrapfd(tty)) {
+ void => return errors::unsupported,
+ fd: int => fd,
+ };
let wsz = rt::winsize { ... };
return match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *void)) {
e: rt::errno => switch (e: int) {