2
votes

I'd like to get the piped content in stdin of a D program only IF it is there.

Considering the following

string output;
char[] buf;
while (stdin.readln(buf))
{
    output ~= buf;
}
return output;

This works great if you pipe content e.g

echo "poop" | test.exe

will print out "poop" and continue execution.

However if you just run test.exe, it will hang there waiting for CTRL+C before continuing.

I'd like to assess the fact that content has been piped in so that I'm not doing a readline() if there is no piped content.

Any clues? Thanks!

1
if you just run test.exe you can type any input - ratchet freak
it is specifically waiting for end of file, which you can signal on Windows using ctrl+z - this lets you type up the info you want sent to the program then signal that you're done so it can begin processing it. - Adam D. Ruppe

1 Answers

4
votes

There's two ways you can do this: ask if data is available on stdin with a timeout, or see if stdin is a pipe or the user-interactive console. Both of these are platform specific; the D std library doesn't include a function to check them. Since you're talking exe, I'll give an answer for Windows. (If you aren't on Windows, the posix functions you want are probably select and isatty, search the web for info about them. You could also set the files to non-blocking mode and try to read.)

To check if data is available, you can call WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 50). The second argument is a timeout in milliseconds - 50 will be quick enough that it looks basically instant to a user, while giving a program time to pipe stuff to it. It will return zero if the object is ready; if there's data available.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032%28v=vs.85%29.aspx

WaitForSingleObject and STD_INPUT_HANDLE are both defined in D by first doing import core.sys.windows.windows;

import core.sys.windows.windows;
import std.stdio;

void main() {
        if(WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 50) == 0) {
                string output;
                char[] buf;
                while (stdin.readln(buf))
                {
                    output ~= buf;
                }
                writeln(output);
        }
}

To tell if stdin is a console.... well, to be honest with you, I don't remember how to do it in Win32 off the top of my head and need to go right now! Maybe I can come back later tonight and edit it in, but if you can find a C solution, the same thing can be done in D too.

See also my comment on the question about end-of-file.