Forum Navigation
Reading output from child process
Moderators:
kris
Posted: 05/29/07 14:05:10It seems that LineIterator? reads output from child process incorrectly. DMD v.1.014, Tango 0.98, WinXP-SP2
There is extract from my program:
module runner; import tango.core.Exception; import tango.io.Conduit; import tango.io.Console; import tango.io.Stdout; import tango.sys.Environment; import tango.sys.Process; import tango.text.Util; import tango.text.stream.LineIterator; // Exception for a case when process finishes with non-zero status. // Exception stores content of STDERR of terminated process. class NonZeroProcessStatusException : TracedException { this( char[] msg, char[][] stderr ) { super( msg ); stderr_ = stderr.dup; } char[][] stderr() { return stderr_; } private : char[][] stderr_; } V[K] merge(K, V)( ref V[K] receiver, in V[K] source ) { foreach( k, v; source ) receiver[ k ] = v; return receiver; } // Launches specified process and returns content of its STDOUT. // Throws NonZeroProcessStatusException if process finishes with // non-zero status. char[][] launchProcess( char[][] commandLine, char[][char[]] env, char[] workingPath = null ) { version(USE_LINE_ITERATOR) { char[][] readProcessStream( Conduit conduit ) { char[][] r; foreach( line; new LineIterator!(char)( conduit ) ) r ~= line; return r; } } else { char[][] readProcessStream( Conduit conduit ) { char[] tmp; char[ 256 ] buf; while( conduit.isReadable ) { uint count = conduit.read( buf ); if( cast(uint)-1 != count ) tmp ~= buf[ 0..count ]; else break; } return splitLines( tmp ); } } typeof(env) fullEnv; merge( fullEnv, Environment.get ); merge( fullEnv, env ); auto p = new Process( commandLine, fullEnv ); if( workingPath ) p.workDir = workingPath; p.execute(); auto output = readProcessStream( p.stdout ); auto stderr = readProcessStream( p.stderr ); auto launchResult = p.wait(); if( 0 != launchResult.status ) throw new NonZeroProcessStatusException( "Process '" ~ p.toUtf8 ~ "' non-zero status: '" ~ launchResult.toUtf8 ~ "'", stderr ); return output; } int main( char[][] args ) { try { char[][char[]] dummyEnv; auto output = launchProcess( args[ 1..$ ], dummyEnv ); foreach( l; output ) Stdout( "'" ~ l ~ "'" ).newline; } catch( NonZeroProcessStatusException x ) { Cerr( "Exception: " ~ x.toUtf8 ~ "\nStderr:\n" ); foreach( line; x.stderr ) Cerr( "\t" ~ line ~ "\n" ); Cerr.flush; return 1; } catch( Exception x ) { Cerr( "*** Exception caught:\n\t" )( x ).newline.flush; return 2; } return 0; } // vim:ts=2:sts=2:sw=2:expandtabI compile it as:
dmd -ofrunner.exe -version=USE_LINE_ITERATOR runner.d tango.libHere is sample program which simple outputs his arguments:
import tango.io.Stdout; int main( char[][] args ) { foreach( a; args[ 1..$ ] ) Stdout( a ).newline; return 0; } // vim:ts=2:sts=2:sw=2:expandtabWhen I run runner.exe with command line:
runner.exe printer.exe " main " "----------------" " 20006"I have the following output:
'---------------' '----------------' ' 20006'But if I compile runner.d as:
dmd -ofrunner.exe runner.d tango.liband run it with the same command line I have correct output:
' main ' '----------------' ' 20006'And yet another question: is it right that tango.io.Conduit.read returns -1 at the end of stream? (It seems that tango.io.Conduit.isReadable returns true always in my sample).
Regards, Yauheni Akhotnikau