Subject: Binary / Text mode question
From: "Trautwein, Marten" <[email-masked]>
To: "[email-masked]'" <[email-masked]>
Cc: "Trautwein, Marten" <[email-masked]>
Date: Wed, 19 Jun 2002 09:26:11 +0100

Dear All,

The following snippet of code runs well on my development NT4.0 system, but
does not do anything on my test NT4.0 system. I compared the  environments
of the two systems, but could not find any significant differences. Could
the problem be caused by the default mode in which the  pipe is opened? (I
did not really get the explanation in the documentation.)

<code-snippet>
#define TRACE_START(a)	fprintf(stderr, "[-- Starting to " a " --]\n"),\
fflush(stderr)
#define TRACE_FINISH(a)	fprintf(stderr, "[-- Finished to " a " --]\n"),\
fflush(stderr)

/* Return NULL on error */
FILE* open_pipe(char* cmd, char mode)
{
    FILE* pipe = NULL;
    TRACE_START("open pipe");
    
    if ( gVerbose )
    {
	fprintf(stderr,
		"[D] Trying to open pipe for '%s' (%s)\n",
		gCommand, gOpenModes[gMode]);
    }
    if ( (pipe = popen(gCommand, gOpenModes[gMode])) == NULL ) 
    {
	fprintf(stderr,
		"[E] Failed to open pipe for '%s' (%s)\n",
		gCommand, gOpenModes[gMode]);
	perror("\tpopen() call");
    }
    else
    {
	fprintf(stderr,
		"[I] Successfully opened pipe for '%s' (%s): %p\n",
		gCommand, gOpenModes[gMode], pipe);
    }
    
    TRACE_FINISH("open pipe");
    return pipe;
}

/* Return negative on error */
int close_pipe(FILE* pipe)
{
    int rval = 0;
    TRACE_START("close pipe");
    
    if ( gVerbose )
    {
	fprintf(stderr,
		"[D] Trying to close pipe %p\n",
		pipe);
    }
    if ( pipe && 
	 (rval = pclose(pipe)) == -1 )
    {
	fprintf(stderr,
		"[E] Failed to close pipe (%p) (err: %d)\n",
		pipe, errno);
	perror("\tpclose() call");
    }
    else
    {
	fprintf(stderr,
		"[I] Successfully closed pipe (%p):\n"
		" Pipe process (%s) returned %d\n", 
		pipe, gCommand, rval );
    }
    TRACE_FINISH("close pipe");
    return rval;
}

/* Read pipe until end of file. */
void read_pipe(FILE* pipe) 
{
    char buffer[BUFSIZ];
    int lines=0, bytes=0;
    TRACE_START("read pipe");
    
    if ( gVerbose )
    {
	fprintf(stderr,
		"[D] Trying to read complete pipe %p\n",
		pipe);
    }
    /* Read pipe until end of file. End of file indicates that 
     * pipe closed its standard out (probably meaning it 
     * terminated).
     */
    while ( !feof(pipe) )
    {
	*buffer='\0';
	if ( gVerbose )
	{
	    fprintf(stderr,
		    "[D] Reading (max. %d bytes) from pipe %p into buffer
%p\n",
		    BUFSIZ, pipe, buffer);
	}
	if ( fgets(buffer, BUFSIZ, pipe) != NULL )
	{
	    lines++;
	    bytes += strlen(buffer);
	    fprintf(stderr, buffer);
	}
	if ( gVerbose )
	{
	    fprintf(stderr,
		    "[D] Read %d bytes from pipe %p into buffer %p\n",
		    strlen(buffer), pipe, buffer);
	}
    }
    if ( gVerbose )
    {
	fprintf(stderr,
		"[D] Reading of pipe %p completed: end of input or error\n",
		pipe);
	perror("\tread pipe");
    }
    fprintf(stderr,
	    "[I] In total read %d lines and %d bytes from pipe (%p)\n", 
	    lines, bytes, pipe);
        
    TRACE_FINISH("read pipe");
    return;
}

/* Read stdin until end of file and write everything to pipe */
void write_pipe(FILE* pipe) 
{
    char buffer[BUFSIZ];
    int lines=0, bytes=0;
    TRACE_START("write pipe");
    
    if ( gVerbose )
    {
	fprintf(stderr,
		"[D] Trying to write to pipe %p\n",
		pipe);
    }
    /* Read stdin until end of file and write to pipe. 
     * End of file on stdin indicates that stdin closed.
     * End of file on pipe indicates error.
     */
    while ( !feof(stdin) )
    {
	if ( gVerbose )
	{
	    fprintf(stderr,
		    "[D] Reading (max. %d bytes) from stdin into buffer
%p\n",
		    BUFSIZ, buffer);
	}
	if ( fgets(buffer, BUFSIZ, stdin) != NULL )
	{
	    if ( gVerbose )
	    {
		fprintf(stderr,
			"[D] Writing %d bytes from stdin/buffer into pipe
%p\n",
			strlen(buffer), pipe);
	    }
	    if ( fputs(buffer, pipe) == EOF )
	    {
		/* Error occurred */
		fprintf(stderr,
			"[E] Failed to write buffer to pipe (%p):\t\n%s\n",
			pipe, buffer);
		perror("\twrite pipe");
	    }
	    else
	    {
		lines++;
		bytes += strlen(buffer);
		fprintf(stderr,
			"[I] Successfully wrote buffer to pipe
(%p):\t\n%s\n",
			pipe, buffer);
	    }
	    if ( gVerbose )
	    {
		fprintf(stderr,
			"[D] Trying to flush pipe %p\n",
			pipe);
	    }
	    if ( fflush(pipe) == EOF )
	    {
		/* Error occurred */
		fprintf(stderr,
			"[E] Failed to flush pipe (%p)\n",
			pipe);
		perror("\tflush pipe");
	    }
	    else
		fprintf(stderr,
			"[I] Successfully flushed pipe (%p)\n",
			pipe);
	}
    }
    if ( gVerbose )
    {
	fprintf(stderr,
		"[D] Reading of stdin completed: end of input or error\n",
		pipe);
	perror("\tread stdin");
    }
    fprintf(stderr,
	    "[I] In total wrote %d lines and %d bytes to pipe (%p)\n", 
	    lines, bytes, pipe);
        
    TRACE_FINISH("write pipe");
    return;
}
</code-snippet>

The snippet describes a test program to test the popen() function call. The
test program has two modes:
1. open a read-pipe to a command, read the pipe's output and write the
output to stderr;
2. open a write-pipe to a command, read from stdin and write the contents to
the pipe.
Both modes work well on my development system, as shown by the following
output.

<read-pipe>
poptest -v r 'echo hello'
[I] Pipe command:'echo hello'
        Pipe mode: r
[-- Starting to open pipe --]
[D] Trying to open pipe for 'echo hello' (r)
[I] Successfully opened pipe for 'echo hello' (r): 0xa0118a4
[-- Finished to open pipe --]
[-- Starting to read pipe --]
[D] Trying to read complete pipe 0xa0118a4
[D] Reading (max. 1024 bytes) from pipe 0xa0118a4 into buffer 0x240fa64
hello
[D] Read 6 bytes from pipe 0xa0118a4 into buffer 0x240fa64
[D] Reading (max. 1024 bytes) from pipe 0xa0118a4 into buffer 0x240fa64
[D] Read 0 bytes from pipe 0xa0118a4 into buffer 0x240fa64
[D] Reading of pipe 0xa0118a4 completed: end of input or error
        read pipe: error 0
[I] In total read 1 lines and 6 bytes from pipe (0xa0118a4)
[-- Finished to read pipe --]
[-- Starting to close pipe --]
[D] Trying to close pipe 0xa0118a4
[I] Successfully closed pipe (0xa0118a4):
 Pipe process (echo hello) returned 0
[-- Finished to close pipe --]
</read-pipe>

<write-pipe>
echo my stdin input string| poptest -v w wc.exe
[I] Pipe command:'wc.exe'
        Pipe mode: w
[-- Starting to open pipe --]
[D] Trying to open pipe for 'wc.exe' (w)
[I] Successfully opened pipe for 'wc.exe' (w): 0xa0118bc
[-- Finished to open pipe --]
[-- Starting to write pipe --]
[D] Trying to write to pipe 0xa0118bc
[D] Reading (max. 1024 bytes) from stdin into buffer 0x240fa64
[D] Writing 22 bytes from stdin/buffer into pipe 0xa0118bc
[I] Successfully wrote buffer to pipe (0xa0118bc):
my stdin input string

[D] Trying to flush pipe 0xa0118bc
[I] Successfully flushed pipe (0xa0118bc)
[D] Reading (max. 1024 bytes) from stdin into buffer 0x240fa64
[D] Reading of stdin completed: end of input or error
        read stdin: error 0
[I] In total wrote 1 lines and 22 bytes to pipe (0xa0118bc)
[-- Finished to write pipe --]
[-- Starting to close pipe --]
[D] Trying to close pipe 0xa0118bc
      1       4      22
[I] Successfully closed pipe (0xa0118bc):
 Pipe process (wc.exe) returned 0
[-- Finished to close pipe --]
</write-pipe>

On the test system, the read mode opens the pipe, reads nothing from the
pipe, closes the pipe successfully and returns with implementation
dependent return value 32512. The write mode crashes (without core-dump) as
soon as I try to flush (or close) the pipe. Below you find the  output of
the test system.

<read-pipe>
poptest -v r 'echo hello'
[I] Pipe command:'echo hello'
        Pipe mode: r
[-- Starting to open pipe --]
[D] Trying to open pipe for 'echo hello' (r)
[I] Successfully opened pipe for 'echo hello' (r): 0x457060c
[-- Finished to open pipe --]
[-- Starting to read pipe --]
[D] Trying to read complete pipe 0x457060c
[D] Reading (max. 1024 bytes) from pipe 0x457060c into buffer 0x253f7bc
[D] Read 0 bytes from pipe 0x457060c into buffer 0x253f7bc
[D] Reading of pipe 0x457060c completed: end of input or error
        read pipe: error 0
[I] In total read 0 lines and 0 bytes from pipe (0x457060c)
[-- Finished to read pipe --]
[-- Starting to close pipe --]
[D] Trying to close pipe 0x457060c
[I] Successfully closed pipe (0x457060c):
 Pipe process (echo hello) returned 32512
[-- Finished to close pipe --]
</read-pipe>

<write-pipe>
echo my stdin input string| poptest -v w wc.exe
[I] Pipe command:'wc.exe'
        Pipe mode: w
[-- Starting to open pipe --]
[D] Trying to open pipe for 'wc.exe' (w)
[I] Successfully opened pipe for 'wc.exe' (w): 0x457060c
[-- Finished to open pipe --]
[-- Starting to write pipe --]
[D] Trying to write to pipe 0x457060c
[D] Reading (max. 1024 bytes) from stdin into buffer 0x253f7bc
[D] Writing 22 bytes from stdin/buffer into pipe 0x457060c
[I] Successfully wrote buffer to pipe (0x457060c):
my stdin input string

[D] Trying to flush pipe 0x457060c
</write-pipe>

Any help or suggestions are highly appreciated.

Regards,

Marten Trautwein

Dr M.H. Trautwein
Perot Systems Nederland B.V.
P.O. Box 2729
3800 GG Amersfoort
The Netherlands
Tel: +31 33 4534545
Fax: +31 33 4534550
Email: [email-masked]
Website: www.perotsystems.nl

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/