Add support for piping using other file descriptor than fd 1

darcs-hash:20051007140857-ac50b-314a47d98ccd09e837be7bd81ebe58d5144c3499.gz
This commit is contained in:
axel 2005-10-08 00:08:57 +10:00
parent 8ff36deeb4
commit 1917ce96f4
6 changed files with 78 additions and 25 deletions

View File

@ -155,9 +155,7 @@ equivalent.
The user can string together multiple commands into a so called
pipeline. This means that the standard output of one command will be read
in as standard input into the next command. This is done by separating
the commands by the pipe character (|).
For example
the commands by the pipe character (|). For example
<tt>cat foo.txt | head</tt>
@ -169,6 +167,17 @@ to combine commands through pipes, read the manual pages of the
commands you want to use using the 'man' command. If you want to find
out more about the 'cat' program, type <tt>man cat</tt>.
Pipes usually connect file descriptor 1 (standard output) of the first
process to file descriptor 0 (standard input) of the second
process. It is possible use a different output file descriptor by
prepending it to the pipe symbol, just like you would do with normal
IO redirections. For example:
<tt>make fish 2|less</tt>
will attempt to build the fish program, and any errors will be shown
using the less pager.
\subsection syntax-background Background jobs
When you start a job in \c fish, \c fish itself will pause, and give

24
exec.c
View File

@ -142,14 +142,14 @@ static int use_fd_in_pipe( int fd, io_data_t *io )
if( !io )
return 0;
if( (io->io_mode == IO_PIPE) ||
(io->io_mode == IO_BUFFER) )
if( ( io->io_mode == IO_BUFFER ) ||
( io->io_mode == IO_PIPE ) )
{
if( io->pipe_fd[0] == fd ||
io->pipe_fd[1] == fd )
return 1;
}
return use_fd_in_pipe( fd, io->next );
}
@ -256,7 +256,10 @@ static void handle_child_io( io_data_t *io )
free_fd( io, io->fd );
}
/*
We don't mind if this fails, it is just a speculative close
to make sure no unexpected untracked fd causes us to fail
*/
while( close(io->fd) == -1 )
{
if( errno != EINTR )
@ -323,22 +326,22 @@ static void handle_child_io( io_data_t *io )
p->pid,
io->pipe_fd[io->fd] );
*/
int fd_to_dup = io->fd;//io->io_mode==IO_BUFFER?1:(io->fd?1:0);
int fd_to_dup = io->fd;
if( dup2( io->pipe_fd[fd_to_dup], io->fd ) == -1 )
if( dup2( io->pipe_fd[fd_to_dup?1:0], io->fd ) == -1 )
{
debug( 1, PIPE_ERROR );
wperror( L"dup2" );
exit(1);
}
if( fd_to_dup )
if( fd_to_dup != 0 )
{
close_loop( io->pipe_fd[0]);
close_loop( io->pipe_fd[1]);
}
else
close_loop( io->pipe_fd[fd_to_dup] );
close_loop( io->pipe_fd[0] );
/*
if( close( io[i].pipe_fd[ io->fd ] ) == -1 )
@ -797,9 +800,11 @@ void exec( job_t *j )
pipe_write.fd=1;
pipe_read.io_mode=IO_PIPE;
pipe_read.pipe_fd[0] = -1;
pipe_read.pipe_fd[1] = -1;
pipe_write.io_mode=IO_PIPE;
pipe_read.next=0;
pipe_write.next=0;
pipe_write.pipe_fd[0]=pipe_write.pipe_fd[1]=0;
//fwprintf( stderr, L"Run command %ls\n", j->command );
@ -818,6 +823,8 @@ void exec( job_t *j )
mypipe[1]=-1;
skip_fork=0;
pipe_write.fd = p->pipe_fd;
/*
This call is used so the global environment variable array is
regenerated, if needed, before the fork. That way, we avoid a
@ -1269,7 +1276,6 @@ void exec( job_t *j )
debug( 3, L"Job is constructed" );
j->io = io_remove( j->io, &pipe_read );
j->io = io_remove( j->io, &pipe_write );
for( tmp = block_io; tmp; tmp=tmp->next )
j->io = io_remove( j->io, tmp );

View File

@ -934,7 +934,7 @@ static void parse_job_main_loop( process_t *p,
tok_get_pos( tok ) );
return;
}
p->pipe_fd = wcstol( tok_last( tok ), 0, 10 );
p->argv = list_to_char_arr( args );
p->next = calloc( 1, sizeof( process_t ) );
if( p->next == 0 )

23
proc.c
View File

@ -565,13 +565,22 @@ int job_do_notification()
j->notified = 1;
if( !j->skip_notification )
{
fwprintf( stdout,
L"fish: %ls %d, \'%ls\' terminated by signal %ls (%ls)",
proc_is_job?L"Job":L"Process",
proc_is_job?j->job_id:p->pid,
j->command,
sig2wcs(WTERMSIG(p->status)),
sig_description( WTERMSIG(p->status) ) );
if( proc_is_job )
fwprintf( stdout,
L"fish: Job %d, \'%ls\' terminated by signal %ls (%ls)",
j->job_id,
j->command,
sig2wcs(WTERMSIG(p->status)),
sig_description( WTERMSIG(p->status) ) );
else
fwprintf( stdout,
L"fish: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)",
p->pid,
p->argv[0],
j->job_id,
j->command,
sig2wcs(WTERMSIG(p->status)),
sig_description( WTERMSIG(p->status) ) );
tputs(clr_eol,1,&writeb);
fwprintf (stdout, L"\n" );
found=1;

2
proc.h
View File

@ -92,6 +92,8 @@ typedef struct process{
INTERNAL_BUILTIN, \c INTERNAL_FUNCTION, \c INTERNAL_BLOCK
*/
int type;
/** File descriptor that pipe output should bind to */
int pipe_fd;
/** true if process has completed */
volatile int completed;
/** true if process has stopped */

View File

@ -38,6 +38,11 @@
*/
#define INPUT_ERROR L"Invalid input"
/**
Error string for when trying to pipe from fd 0
*/
#define PIPE_ERROR L"Can not use fd 0 as pipe output"
/**
Characters that separate tokens. They are ordered by frequency of occurrence to increase parsing speed.
*/
@ -489,10 +494,6 @@ void tok_next( tokenizer *tok )
switch( *tok->buff )
{
case L'|':
tok->last_type = TOK_PIPE;
tok->buff++;
break;
case L'\0':
tok->last_type = TOK_END;
/*fwprintf( stderr, L"End of string\n" );*/
@ -509,6 +510,15 @@ void tok_next( tokenizer *tok )
tok->buff++;
break;
case L'|':
check_size( tok, 16 );
tok->last[0]=L'1';
tok->last[1]=L'\0';
tok->last_type = TOK_PIPE;
tok->buff++;
break;
case L'>':
return read_redirect( tok, 1 );
case L'<':
@ -520,14 +530,31 @@ void tok_next( tokenizer *tok )
if( iswdigit( *tok->buff ) )
{
int fd = *tok->buff - L'0';
check_size( tok, 16 );
switch( *(tok->buff+1))
{
case L'|':
{
if( fd == 0 )
{
tok_error( tok, PIPE_ERROR );
return;
}
tok->buff+=2;
tok->last[0]=L'0'+fd;
tok->last[1]=L'\0';
tok->last_type = TOK_PIPE;
return;
}
case L'>':
case L'<':
{
tok->buff++;
read_redirect( tok, fd );
return;
}
}
}
read_string( tok );