I'm writing a Vala program which is spawned as a child_process using stdout & stdin for message transfer with parent. In an async method I call read_stdin(sb) to check for incoming messages. I tried various stdin methods like gets and getc, but they all appear to block on '\n' newline. I need to read all chars available and return immediately (non-blocking).
const int STDIN_BUF_SIZE=1024;
char[] stdin_buffer;
bool read_stdin (StringBuilder sb) {
int iPos=0;
int c;
int buf_size=STDIN_BUF_SIZE-1;
// Char by char:
while (true) {
c = stdin.getc ();
if(c == GLib.FileStream.EOF) break;
stdin_buffer[iPos]=(char)c;
iPos++;
if ((char)c=='\n'||iPos==buf_size){
break;
}
}
if(iPos>0){
stdin_buffer[iPos]=0;
sb.append((string)stdin_buffer);
return true;
}
return false;
}
Can stdin be used for non-blocking IO or do I need to create something like...
DataInputStream stdin_reader = new DataInputStream(stdin);
You use the term "non-blocking", but I don't think that means what you think it means. It would be pretty easy to simply open /dev/stdin
with O_NONBLOCK
if non-blocking I/O was what you really wanted. In that case, getc
would instantly return EOF
until there is data available.
AFAICT, what you want is actually for the getc
call to block until new data is available, then immediately return. Technically, that's what is happening. The wrinkle is that terminal applications typically buffer data until a newline, which explains why you can edit data and not have any edits appear to your application; go ahead, try typing "AB" into your program, and all you'll see will be "B\n".
Basically, you need to use a curses library. Vala includes a curses.vapi, so you should just need to link to the relevant library (probably ncurses) and add --pkg curses
to your valac
invocation and you'll be good to go. IIRC the relevant function is getch
, but I haven't done any curses programming in a long time.