How would I convert an os.Handle to a c.FILE pointer?

I’m porting the function isatty that’s commonly found in POSIX systems and also implemented on Windows. It’s currently implemented like this:

package utils

import c "core:c/libc"
import "core:fmt"
import "core:os"

when ODIN_OS == .Windows {
  foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
  foreign import libc "system:System.framework"
} else {
  foreign import libc "system:c"
}

@(private)
IS_TTY_LINKNAME :: "isatty" when ODIN_OS != .Windows else "_isatty"
@(private)
FILENO_LINKNAME :: "fileno" when ODIN_OS != .Windows else "_fileno"

foreign libc {
  @(link_name = IS_TTY_LINKNAME, private)
  isatty :: proc(fd: c.int) -> c.int ---
  @(link_name = FILENO_LINKNAME, private)
  fileno :: proc(stream: ^c.FILE) -> c.int ---
}

is_tty :: proc(fd: ^c.FILE) -> b32 {
  return transmute(b32)isatty(fileno(c.stdout))
}

But I think it would be better if is_tty could receive an os.handle instead of a ^c.File. How can I do it?

(I know fileno could be public but I want to eventually make a wrapper that receives an os.Handle and I would run into the same problem)

1 Like

The os.Handle is a HANDLE on Windows, and a file descriptor on posix platforms. Knowing that you can write something like the following:

import "core:sys/windows"
import "core:sys/posix"

is_tty :: proc(fd: os.Handle) -> bool {
    when ODIN_OS == .Windows {
        ft := windows.GetFileType(windows.HANDLE(fd))
        return ft == windows.FILE_TYPE_CHAR
    } else {
        return bool(posix.isatty(posix.FD(fd)))
    }
}
2 Likes