Search code examples
pipedstdinreadlinereadlines

D Programming - How to get the piped content from stdin


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!


Solution

  • 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.