interacting with an interactive cli program

S

Stephan Steiner

Hi

I'm trying to write a program that interacts with an interactive cli
program, that is a program that does some processing but every now and then
requires some user input. My problem is that when I redirect stdin and
stdout of the program I launch, the program seems to run but I never get any
output from it. But if I don't redirect its stdout, I see how it's just
sitting there waiting for my input. To illustrate the problem and make
testing easier I wrote two very small programs, one simulating my
interactive program:

static void Main(string[] args)
{
Console.Write("Login[]");
Console.ReadLine();
Console.Write("\r\nPassword[]:");
Console.ReadLine();
Console.Write("\r\nDo you wish to continue? y/n");
string answer = Console.ReadLine();
if (answer.Equals("y"))
Console.WriteLine("yippie");
else
Console.WriteLine("aborting");
}

And the one supposed to handle this cli program:

static void main(string[] args)
{
ProcessStartInfo psi = new ProcessStartInfo("c:\\temp\\inputreader.exe");
psi.RedirectStandardOutput=true;
psi.RedirectStandardInput=true;
psi.UseShellExecute=false;
psi.CreateNoWindow=true;
Process proc = Process.Start(psi);
StreamReader reader = proc.StandardOutput;
string line = "";
while ((line = reader.ReadLine())!=null)
{
if (line.Equals("Login[]"))
{
proc.StandardInput.WriteLine("login");
}
if (line.Equals("Password[]:"))
{
proc.StandardInput.WriteLine("password");
}
if (line.Equals("Do you wish to continue? y/n"))
{
proc.StandardInput.WriteLine("y");
}
}
}

If anybody could tell me where I'm going wrong I'd much appreciate it.

Regards
Stephan
 
J

Jon Skeet [C# MVP]

Stephan Steiner said:
I'm trying to write a program that interacts with an interactive cli
program, that is a program that does some processing but every now and then
requires some user input. My problem is that when I redirect stdin and
stdout of the program I launch, the program seems to run but I never get any
output from it. But if I don't redirect its stdout, I see how it's just
sitting there waiting for my input. To illustrate the problem and make
testing easier I wrote two very small programs, one simulating my
interactive program:

<snip>

The problem is that you're using Console.Write instead of
Console.WriteLine - so you're never finishing the current line, so
reader.ReadLine() can never return.
 
S

Stephan Steiner

The problem is that you're using Console.Write instead of
Console.WriteLine - so you're never finishing the current line, so
reader.ReadLine() can never return.

Ahh, now I get it. Thanks.

This solves the problems with my test program, but I'm still not quite done
with the one I really want to launch (the Cisco VPN client). Basically I
know it writes entire lines to stdout, but if it requires manual input, any
proc.StandardOutput.Read/ReadLine/Peek blocks indefinitely. Even a C++
sample I found that redirects cmd.exe into a window blocks when I launch the
VPNClient so I know it's not the language and the mechanism I'm catching
stdin and stdout also seems to be okay so I'm wondering what more it could
be.

Do you have any idea what could be the reason that even if my stdin/stdout
writer/reader program waits until I know for sure that the vpnclient I have
launched is waiting for an input (all I have to do is not redirect stdout to
see), a simple proc.StandardOutput.Peek blocks indefinitely?

Regards
Stephan
 
J

Jon Skeet [C# MVP]

Stephan Steiner said:
Ahh, now I get it. Thanks.

This solves the problems with my test program, but I'm still not quite done
with the one I really want to launch (the Cisco VPN client). Basically I
know it writes entire lines to stdout, but if it requires manual input, any
proc.StandardOutput.Read/ReadLine/Peek blocks indefinitely. Even a C++
sample I found that redirects cmd.exe into a window blocks when I launch the
VPNClient so I know it's not the language and the mechanism I'm catching
stdin and stdout also seems to be okay so I'm wondering what more it could
be.

Do you have any idea what could be the reason that even if my stdin/stdout
writer/reader program waits until I know for sure that the vpnclient I have
launched is waiting for an input (all I have to do is not redirect stdout to
see), a simple proc.StandardOutput.Peek blocks indefinitely?

Hmm... not sure, to be honest. It may well be doing some strange stuff
with the console to (for instance) make passwords get echoed as ****
etc. If that's the case, you probably won't have much luck - but maybe
someone else here knows more about it...
 
S

Stephan Steiner

Hmm... not sure, to be honest. It may well be doing some strange stuff
with the console to (for instance) make passwords get echoed as ****
etc. If that's the case, you probably won't have much luck - but maybe
someone else here knows more about it...

I tend to agree with your assessment. I've just come across a resolved bug
when reading the cisco vpn client release notes.. it was about piping
stdin/stdout not working properly. Maybe they've reintroduced that bug in
the latest version that I'm using. I have now contacted Cisco about this as
I'm not able to find the error on my end. I was not even able to just
redirect stdin and look at how it plays out seeing stdout on screen.

Regards
Stephan
 
S

Stephan Steiner

Hmm... not sure, to be honest. It may well be doing some strange stuff
with the console to (for instance) make passwords get echoed as ****
etc. If that's the case, you probably won't have much luck - but maybe
someone else here knows more about it...

I've managed to get it working - the Cisco VPN Client was at fault and I had
to downgrade to an older version that does not have any issues with
redirecting stdin/stdout. But I've come across another thing that I find
quite strange. I realized that I could send all my input to stdin right
away, then just let her rip so to speak and read every line from the stdout
until the process exists (well, it's a bit more complex as the process is
not ended unless you start another instance of the vpnclient and tell it to
disconnect, which also leads to the termination of the first vpnclient).
Anyway, the issue I've come across is this:

Since at first I thought I had to read characters from stdout (which is
correct if I want to enter my input at the appropriate position.. the login
prompt is not an entire line, the curser remains on the same line so
proc.StandardOutput.readLine would block indefinitely), but using
proc.StandardOutput.Peek to check if there's any more data on the stdout is
unreliable. If rather than stepping through the program and read character
by character I stop once peek returns -1, I set a breakpoint after my while
loop that reads from stdout, the while loop is ended prematurely. And while
peek returns -1, a proc.StandardOutput.readLine still returns valid lines.
Is there a peeping Tom protection in Peek? What could cause Peek to
return -1 when ReadLine returns a valid line?

And in code in case my explanation was a bit complicated:

char[] blub = new char[1];
int peakval = 0;
StreamReader reader = proc.StandardOutput;
while ((peakval = reader.Peek()) != -1)
{
proc.StandardOutput.Read(blub, 0, 1);
Console.Write(blub, 0, 1);
}

does not yield the same result as

StreamReader reader = proc.StandardOutput;
string line = "";
while ((line = reader.ReadLine())!=null)
{
Console.WriteLine(line);
}

The latter gets all the lines, the former does not. But putting the two
after each other, the ReadLine based while gets the remaning lines from the
stdout. The inverse (forcefully aborting the ReadLine based while loop is
required though), does not work.
Regards
Stephan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top