I'm probably missing something really obvious, but how are you supposed to handle a scenario where you read a file from stdin and then need to prompt for a password after doing so.
e.g. something like this:
cat sometextfile.txt | myapp -
Password: blahblah
readAll(stdin) works fine to grab the content on the first line, but readPasswordFromStdin returns nothing after that.
I wondered if I have to close and re-open stdin, but that doesn't look like it works. Any clues to the voodoo required here?
I thought this might work:
proc fseek(f: File, offset: clong, whence: int): int {.importc: "fseek", header: "<stdio.h>", tags: [].}
var s1 = readAll(stdin)
discard fseek(stdin, 0, 0)
var s2 = readPasswordFromStdin("\ntest: ")
But turns out, it only works if you don't pipe the input into the first call to readAll (i.e. typed input works, "cat sometextfile.txt | myapp" doesn't.
To interact with the terminal, you need to read from /dev/tty on Unix systems, as stdin may be redirected to a non-tty input source. Here's a quick and dirty adaptation of the readPasswordFromStdin code for /dev/tty (warning, I did only minimal testing):
import termios
proc readPasswordfromTty*(prompt: string): string =
var tty = open("/dev/tty", fmReadWrite)
let fd = tty.getFileHandle()
var cur, old: Termios
discard fd.tcgetattr(addr cur)
old = cur
cur.c_lflag = cur.c_lflag and not Cflag(ECHO)
discard fd.tcsetattr(TCSADRAIN, addr cur)
tty.write prompt
tty.flushFile
result = tty.readLine
tty.close
discard fd.tcsetattr(TCSADRAIN, addr old)
import strutils
proc main =
let s = readPasswordfromTty("> ")
echo repeatChar(len(s), '*')
echo s
main()