2005-09-20 13:26:39 +00:00
/** \file builtin.c
Functions for executing builtin functions .
How to add a new builtin function :
1 ) . Create a function in builtin . c with the following signature :
< tt > static int builtin_NAME ( wchar_t * * args ) < / tt >
2006-01-30 19:53:10 +00:00
where NAME is the name of the builtin , and args is a zero - terminated list of arguments .
2005-09-20 13:26:39 +00:00
2012-02-01 03:47:56 +00:00
2 ) . Add a line like { L " NAME " , & builtin_NAME , N_ ( L " Bla bla bla " ) } , to the builtin_data_t variable . The description is used by the completion system . Note that this array is sorted !
2005-09-20 13:26:39 +00:00
2006-02-05 21:20:50 +00:00
3 ) . Create a file doc_src / NAME . txt , containing the manual for the builtin in Doxygen - format . Check the other builtin manuals for proper syntax .
2005-09-20 13:26:39 +00:00
2007-07-31 21:23:20 +00:00
4 ) . Use ' darcs add doc_src / NAME . txt ' to start tracking changes to the documentation file .
2005-12-14 23:48:08 +00:00
2005-09-20 13:26:39 +00:00
*/
2006-08-11 01:18:35 +00:00
# include "config.h"
2005-09-20 13:26:39 +00:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <unistd.h>
# include <termios.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <dirent.h>
# include <string.h>
# include <signal.h>
# include <wctype.h>
# include <sys/time.h>
2005-09-24 19:55:58 +00:00
# include <time.h>
2012-02-08 07:53:34 +00:00
# include <stack>
2005-09-20 13:26:39 +00:00
2006-02-28 13:17:16 +00:00
# include "fallback.h"
2005-09-20 13:26:39 +00:00
# include "util.h"
2006-02-28 13:17:16 +00:00
2005-09-20 13:26:39 +00:00
# include "wutil.h"
# include "builtin.h"
# include "function.h"
# include "complete.h"
# include "proc.h"
# include "parser.h"
# include "reader.h"
# include "env.h"
# include "common.h"
# include "wgetopt.h"
# include "sanity.h"
# include "tokenizer.h"
# include "wildcard.h"
# include "input_common.h"
# include "input.h"
# include "intern.h"
2005-10-05 22:37:08 +00:00
# include "event.h"
2005-10-08 11:20:51 +00:00
# include "signal.h"
2006-11-17 16:24:38 +00:00
# include "exec.h"
2007-01-29 16:26:24 +00:00
# include "highlight.h"
2006-02-14 19:56:36 +00:00
# include "parse_util.h"
2007-04-22 09:50:26 +00:00
# include "parser_keywords.h"
2006-02-14 19:56:36 +00:00
# include "expand.h"
2006-10-19 11:50:23 +00:00
# include "path.h"
2005-09-20 13:26:39 +00:00
2006-06-20 21:20:16 +00:00
2005-09-20 13:26:39 +00:00
/**
The default prompt for the read command
*/
# define DEFAULT_READ_PROMPT L"set_color green; echo read; set_color normal; echo \"> \""
/**
The mode name to pass to history and input
*/
# define READ_MODE_NAME L"fish_read"
2005-12-15 13:59:02 +00:00
2005-09-20 13:26:39 +00:00
/**
2005-12-15 13:59:02 +00:00
The send stuff to foreground message
2005-09-20 13:26:39 +00:00
*/
2006-01-04 12:51:02 +00:00
# define FG_MSG _( L"Send job %d, '%ls' to foreground\n" )
2005-12-11 23:30:01 +00:00
2006-06-17 13:07:08 +00:00
/**
2011-12-27 03:18:46 +00:00
Datastructure to describe a builtin .
2006-06-17 13:07:08 +00:00
*/
2012-02-01 03:47:56 +00:00
struct builtin_data_t
2006-02-05 13:08:40 +00:00
{
2006-06-17 13:07:08 +00:00
/**
Name of the builtin
*/
2006-02-05 13:08:40 +00:00
const wchar_t * name ;
2006-06-17 13:07:08 +00:00
/**
Function pointer tothe builtin implementation
*/
2012-01-16 20:10:08 +00:00
int ( * func ) ( parser_t & parser , wchar_t * * argv ) ;
2006-06-17 13:07:08 +00:00
/**
Description of what the builtin does
*/
2006-02-05 13:08:40 +00:00
const wchar_t * desc ;
2012-02-01 03:47:56 +00:00
2012-02-01 04:22:25 +00:00
bool operator < ( const wcstring & ) const ;
2012-02-01 03:47:56 +00:00
bool operator < ( const builtin_data_t * ) const ;
} ;
2006-02-05 13:08:40 +00:00
2012-02-01 04:22:25 +00:00
bool builtin_data_t : : operator < ( const wcstring & other ) const
2012-02-01 03:47:56 +00:00
{
2012-02-01 04:22:25 +00:00
return wcscmp ( this - > name , other . c_str ( ) ) < 0 ;
2012-02-01 03:47:56 +00:00
}
2006-02-05 13:08:40 +00:00
2012-02-01 03:47:56 +00:00
bool builtin_data_t : : operator < ( const builtin_data_t * other ) const
{
return wcscmp ( this - > name , other - > name ) < 0 ;
}
2005-09-20 13:26:39 +00:00
int builtin_out_redirect ;
int builtin_err_redirect ;
2012-02-22 18:51:06 +00:00
/* Buffers for storing the output of builtin functions */
wcstring stdout_buffer , stderr_buffer ;
const wcstring & get_stdout_buffer ( ) {
ASSERT_IS_MAIN_THREAD ( ) ;
return stdout_buffer ;
}
const wcstring & get_stderr_buffer ( ) {
ASSERT_IS_MAIN_THREAD ( ) ;
return stderr_buffer ;
}
2012-03-07 09:02:46 +00:00
void builtin_show_error ( const wcstring & err ) {
ASSERT_IS_MAIN_THREAD ( ) ;
stderr_buffer . append ( err ) ;
}
2005-12-15 13:59:02 +00:00
2005-09-20 13:26:39 +00:00
/**
Stack containing builtin I / O for recursive builtin calls .
*/
2012-02-08 07:53:34 +00:00
struct io_stack_elem_t {
int in ;
2012-02-22 18:51:06 +00:00
wcstring out ;
wcstring err ;
2012-02-08 07:53:34 +00:00
} ;
static std : : stack < io_stack_elem_t > io_stack ;
2005-09-20 13:26:39 +00:00
2006-01-30 19:53:10 +00:00
/**
2006-02-05 21:20:50 +00:00
The file from which builtin functions should attempt to read , use
instead of stdin .
2005-09-20 13:26:39 +00:00
*/
static int builtin_stdin ;
2007-04-25 18:30:02 +00:00
/**
2007-10-06 10:55:27 +00:00
The underlying IO redirections behind the current builtin . This
2007-04-25 18:30:02 +00:00
should normally not be used - sb_out and friends are already
configured to handle everything .
*/
static io_data_t * real_io ;
2006-06-20 21:20:16 +00:00
/**
Counts the number of non null pointers in the specified array
*/
static int builtin_count_args ( wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
int argc = 1 ;
while ( argv [ argc ] ! = 0 )
{
argc + + ;
}
return argc ;
}
2011-12-27 03:18:46 +00:00
/**
2006-06-20 21:20:16 +00:00
This function works like wperror , but it prints its result into
2012-03-04 06:08:34 +00:00
the sb_err string instead of to stderr . Used by the builtin
2006-06-20 21:20:16 +00:00
commands .
*/
2005-10-14 22:33:01 +00:00
2006-06-20 21:20:16 +00:00
static void builtin_wperror ( const wchar_t * s )
2005-09-20 13:26:39 +00:00
{
if ( s ! = 0 )
{
2012-02-22 18:51:06 +00:00
stderr_buffer . append ( s ) ;
stderr_buffer . append ( L " : " ) ;
2005-09-20 13:26:39 +00:00
}
char * err = strerror ( errno ) ;
wchar_t * werr = str2wcs ( err ) ;
if ( werr )
{
2012-02-22 18:51:06 +00:00
stderr_buffer . append ( werr ) ;
stderr_buffer . push_back ( L ' \n ' ) ;
2005-09-20 13:26:39 +00:00
free ( werr ) ;
2006-01-30 19:53:10 +00:00
}
2005-09-20 13:26:39 +00:00
}
2006-06-17 13:07:08 +00:00
/**
Count the number of times the specified character occurs in the specified string
*/
2006-05-26 11:24:02 +00:00
static int count_char ( const wchar_t * str , wchar_t c )
{
int res = 0 ;
for ( ; * str ; str + + )
{
res + = ( * str = = c ) ;
}
return res ;
}
2005-09-20 13:26:39 +00:00
2012-02-01 04:22:25 +00:00
wcstring builtin_help_get ( parser_t & parser , const wchar_t * name )
2006-11-17 16:24:38 +00:00
{
2011-12-31 23:57:30 +00:00
wcstring_list_t lst ;
2012-02-01 04:22:25 +00:00
wcstring out ;
const wcstring name_esc = escape_string ( name , 1 ) ;
const wcstring cmd = format_string ( L " __fish_print_help %ls " , name_esc . c_str ( ) ) ;
2012-02-08 07:35:41 +00:00
if ( exec_subshell ( cmd , lst ) > = 0 )
2011-12-27 03:18:46 +00:00
{
2012-02-01 04:22:25 +00:00
for ( size_t i = 0 ; i < lst . size ( ) ; i + + )
2007-01-09 02:53:56 +00:00
{
2012-02-01 04:22:25 +00:00
out . append ( lst . at ( i ) ) ;
out . push_back ( L ' \n ' ) ;
2007-01-09 02:53:56 +00:00
}
2006-11-17 16:24:38 +00:00
}
2012-02-01 04:22:25 +00:00
return out ;
2006-11-17 16:24:38 +00:00
}
2007-10-02 10:09:37 +00:00
/**
Print help for the specified builtin . If \ c b is sb_err , also print
the line information
If \ c b is the buffer representing standard error , and the help
message is about to be printed to an interactive screen , it may be
shortened to fit the screen .
2011-12-27 03:18:46 +00:00
2007-10-02 10:09:37 +00:00
*/
2006-06-20 21:20:16 +00:00
2012-02-22 18:51:06 +00:00
static void builtin_print_help ( parser_t & parser , const wchar_t * cmd , wcstring & b )
2005-09-20 13:26:39 +00:00
{
2011-12-27 03:18:46 +00:00
2007-01-31 16:03:17 +00:00
int is_short = 0 ;
2011-12-27 03:18:46 +00:00
2012-02-22 18:51:06 +00:00
if ( & b = = & stderr_buffer )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
stderr_buffer . append ( parser . current_line ( ) ) ;
2005-09-20 13:26:39 +00:00
}
2012-02-01 04:22:25 +00:00
const wcstring h = builtin_help_get ( parser , cmd ) ;
2005-09-20 13:26:39 +00:00
2012-02-01 04:22:25 +00:00
if ( ! h . size ( ) )
2005-09-20 13:26:39 +00:00
return ;
2012-02-01 04:22:25 +00:00
wchar_t * str = wcsdup ( h . c_str ( ) ) ;
2005-09-20 13:26:39 +00:00
if ( str )
{
2006-05-26 11:24:02 +00:00
2012-02-22 18:51:06 +00:00
if ( & b = = & stderr_buffer )
2006-05-26 11:24:02 +00:00
{
2011-12-27 03:18:46 +00:00
2006-11-17 16:24:38 +00:00
/*
Interactive mode help to screen - only print synopsis if
2011-12-27 03:18:46 +00:00
the rest won ' t fit
2006-11-17 16:24:38 +00:00
*/
2011-12-27 03:18:46 +00:00
2006-05-26 11:24:02 +00:00
int screen_height , lines ;
2006-10-25 20:28:36 +00:00
2006-05-26 11:24:02 +00:00
screen_height = common_get_height ( ) ;
lines = count_char ( str , L ' \n ' ) ;
2012-02-26 02:54:49 +00:00
if ( ! get_is_interactive ( ) | | ( lines > 2 * screen_height / 3 ) )
2006-05-26 11:24:02 +00:00
{
wchar_t * pos ;
2006-10-25 20:32:25 +00:00
int cut = 0 ;
2006-11-17 16:24:38 +00:00
int i ;
2011-12-27 03:18:46 +00:00
2007-01-31 16:03:17 +00:00
is_short = 1 ;
2011-12-27 03:18:46 +00:00
2006-11-17 16:24:38 +00:00
/*
First move down 4 lines
*/
2011-12-27 03:18:46 +00:00
2006-11-17 16:24:38 +00:00
pos = str ;
2007-04-16 20:10:53 +00:00
for ( i = 0 ; ( i < 4 ) & & pos & & * pos ; i + + )
2006-11-17 16:24:38 +00:00
{
pos = wcschr ( pos + 1 , L ' \n ' ) ;
}
2011-12-27 03:18:46 +00:00
2007-04-16 20:10:53 +00:00
if ( pos & & * pos )
2006-05-26 11:24:02 +00:00
{
2011-12-27 03:18:46 +00:00
/*
Then find the next empty line
2006-11-17 16:24:38 +00:00
*/
for ( ; * pos ; pos + + )
{
if ( * pos = = L ' \n ' )
2006-05-26 11:24:02 +00:00
{
2006-11-17 16:24:38 +00:00
wchar_t * pos2 ;
int is_empty = 1 ;
2011-12-27 03:18:46 +00:00
2006-11-17 16:24:38 +00:00
for ( pos2 = pos + 1 ; * pos2 ; pos2 + + )
2006-05-26 11:24:02 +00:00
{
2006-11-17 16:24:38 +00:00
if ( * pos2 = = L ' \n ' )
break ;
2011-12-27 03:18:46 +00:00
2006-11-17 16:24:38 +00:00
if ( * pos2 ! = L ' \t ' & & * pos2 ! = L ' ' )
{
is_empty = 0 ;
break ;
}
}
if ( is_empty )
{
/*
And cut it
*/
* ( pos2 + 1 ) = L ' \0 ' ;
cut = 1 ;
2006-05-26 11:24:02 +00:00
break ;
}
}
}
}
2011-12-27 03:18:46 +00:00
2006-11-17 16:24:38 +00:00
/*
We did not find a good place to cut message to
shorten it - so we make sure we don ' t print
anything .
*/
2006-10-25 20:32:25 +00:00
if ( ! cut )
{
* str = 0 ;
}
2006-11-17 16:24:38 +00:00
2006-05-26 11:24:02 +00:00
}
}
2011-12-27 03:18:46 +00:00
2012-02-22 18:51:06 +00:00
b . append ( str ) ;
2007-01-31 16:03:17 +00:00
if ( is_short )
{
2012-02-22 18:51:06 +00:00
append_format ( b , _ ( L " %ls: Type 'help %ls' for related documentation \n \n " ) , cmd , cmd ) ;
2007-01-31 16:03:17 +00:00
}
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
free ( str ) ;
}
}
2006-06-20 21:20:16 +00:00
2007-01-21 14:55:27 +00:00
/**
Perform error reporting for encounter with unknown option
*/
2012-01-16 20:10:08 +00:00
static void builtin_unknown_option ( parser_t & parser , const wchar_t * cmd , const wchar_t * opt )
2007-01-21 14:55:27 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , BUILTIN_ERR_UNKNOWN , cmd , opt ) ;
builtin_print_help ( parser , cmd , stderr_buffer ) ;
2007-01-21 14:55:27 +00:00
}
2007-08-01 19:44:50 +00:00
/**
Perform error reporting for encounter with missing argument
*/
2012-01-16 20:10:08 +00:00
static void builtin_missing_argument ( parser_t & parser , const wchar_t * cmd , const wchar_t * opt )
2007-08-01 19:44:50 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , BUILTIN_ERR_MISSING , cmd , opt ) ;
builtin_print_help ( parser , cmd , stderr_buffer ) ;
2007-08-01 19:44:50 +00:00
}
2006-06-20 21:20:16 +00:00
/*
Here follows the definition of all builtin commands . The function
names are all on the form builtin_NAME where NAME is the name of the
builtin . so the function name for the builtin ' fg ' is
' builtin_fg ' .
A few builtins , including ' while ' , ' command ' and ' builtin ' are not
defined here as they are handled directly by the parser . ( They are
not parsed as commands , instead they only alter the parser state )
The builtins ' break ' and ' continue ' are so closely related that they
share the same implementation , namely ' builtin_break_continue .
Several other builtins , including jobs , ulimit and set are so big
that they have been given their own file . These files are all named
2007-01-06 14:24:30 +00:00
' builtin_NAME . c ' , where NAME is the name of the builtin . These files
are included directly below .
2006-06-20 21:20:16 +00:00
*/
2011-12-27 03:18:46 +00:00
# include "builtin_set.cpp"
# include "builtin_commandline.cpp"
# include "builtin_complete.cpp"
# include "builtin_ulimit.cpp"
# include "builtin_jobs.cpp"
2006-06-20 21:20:16 +00:00
2012-03-07 08:54:01 +00:00
/* builtin_test lives in builtin_test.cpp */
int builtin_test ( parser_t & parser , wchar_t * * argv ) ;
2008-01-13 16:47:47 +00:00
/**
List all current key bindings
*/
2007-09-25 16:14:47 +00:00
static void builtin_bind_list ( )
{
2011-12-31 23:57:30 +00:00
size_t i ;
wcstring_list_t lst ;
input_mapping_get_names ( lst ) ;
2011-12-27 03:18:46 +00:00
2011-12-31 23:57:30 +00:00
for ( i = 0 ; i < lst . size ( ) ; i + + )
2007-09-25 16:14:47 +00:00
{
2011-12-31 23:57:30 +00:00
wcstring seq = lst . at ( i ) ;
2011-12-27 03:18:46 +00:00
2011-12-31 23:57:30 +00:00
wcstring ecmd ;
input_mapping_get ( seq , ecmd ) ;
ecmd = escape_string ( ecmd , 1 ) ;
wcstring tname ;
if ( input_terminfo_get_name ( seq , tname ) )
2007-09-25 16:14:47 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , L " bind -k %ls %ls \n " , tname . c_str ( ) , ecmd . c_str ( ) ) ;
2007-09-25 16:14:47 +00:00
}
else
{
2011-12-31 23:57:30 +00:00
const wcstring eseq = escape_string ( seq , 1 ) ;
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , L " bind %ls %ls \n " , eseq . c_str ( ) , ecmd . c_str ( ) ) ;
2011-12-31 23:57:30 +00:00
}
}
2007-09-25 16:14:47 +00:00
}
2008-01-13 16:47:47 +00:00
/**
Print terminfo key binding names to string buffer used for standard output .
\ param all if set , all terminfo key binding names will be
printed . If not set , only ones that are defined for this terminal
are printed .
*/
2007-09-25 16:14:47 +00:00
static void builtin_bind_key_names ( int all )
{
2012-02-08 01:06:45 +00:00
const wcstring_list_t names = input_terminfo_get_names ( ! all ) ;
for ( size_t i = 0 ; i < names . size ( ) ; i + + )
2007-09-25 16:14:47 +00:00
{
2012-02-08 01:06:45 +00:00
const wcstring & name = names . at ( i ) ;
2011-12-27 03:18:46 +00:00
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , L " %ls \n " , name . c_str ( ) ) ;
2007-09-25 16:14:47 +00:00
}
}
2008-01-13 16:47:47 +00:00
/**
Print all the special key binding functions to string buffer used for standard output .
*/
2007-09-25 16:14:47 +00:00
static void builtin_bind_function_names ( )
{
2012-01-24 04:48:47 +00:00
wcstring_list_t names = input_function_get_names ( ) ;
2011-12-27 03:18:46 +00:00
2012-01-24 04:48:47 +00:00
for ( size_t i = 0 ; i < names . size ( ) ; i + + )
2007-09-25 16:14:47 +00:00
{
2012-01-24 04:48:47 +00:00
const wchar_t * seq = names . at ( i ) . c_str ( ) ;
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , L " %ls \n " , seq ) ;
2007-09-25 16:14:47 +00:00
}
}
2008-01-13 16:47:47 +00:00
/**
Add specified key binding .
*/
2007-09-25 16:14:47 +00:00
static int builtin_bind_add ( wchar_t * seq , wchar_t * cmd , int terminfo )
{
if ( terminfo )
{
const wchar_t * seq2 = input_terminfo_get_sequence ( seq ) ;
if ( seq2 )
{
input_mapping_add ( seq2 , cmd ) ;
}
else
{
2007-09-28 21:35:23 +00:00
switch ( errno )
{
case ENOENT :
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , _ ( L " %ls: No key with name '%ls' found \n " ) , L " bind " , seq ) ;
2007-09-28 21:35:23 +00:00
break ;
}
case EILSEQ :
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , _ ( L " %ls: Key with name '%ls' does not have any mapping \n " ) , L " bind " , seq ) ;
2007-09-28 21:35:23 +00:00
break ;
}
default :
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , _ ( L " %ls: Unknown error trying to bind to key named '%ls' \n " ) , L " bind " , seq ) ;
2007-09-28 21:35:23 +00:00
break ;
}
}
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
return 1 ;
}
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
}
else
{
input_mapping_add ( seq , cmd ) ;
}
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
return 0 ;
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
}
2008-01-13 16:47:47 +00:00
/**
Erase specified key bindings
\ param seq an array of all key bindings to erase
\ param all if specified , _all_ key bindings will be erased
*/
2007-09-25 16:14:47 +00:00
static void builtin_bind_erase ( wchar_t * * seq , int all )
{
if ( all )
{
2011-12-31 23:57:30 +00:00
size_t i ;
wcstring_list_t lst ;
input_mapping_get_names ( lst ) ;
2011-12-27 03:18:46 +00:00
2011-12-31 23:57:30 +00:00
for ( i = 0 ; i < lst . size ( ) ; i + + )
2007-09-25 16:14:47 +00:00
{
2011-12-31 23:57:30 +00:00
input_mapping_erase ( lst . at ( i ) . c_str ( ) ) ;
2011-12-27 03:18:46 +00:00
}
2007-09-25 16:14:47 +00:00
}
else
{
while ( * seq )
{
input_mapping_erase ( * seq + + ) ;
}
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
}
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
}
2006-06-20 21:20:16 +00:00
2005-09-20 13:26:39 +00:00
/**
The bind builtin , used for setting character sequences
*/
2012-01-16 20:10:08 +00:00
static int builtin_bind ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2007-09-25 16:14:47 +00:00
enum
{
BIND_INSERT ,
BIND_ERASE ,
BIND_KEY_NAMES ,
BIND_FUNCTION_NAMES
}
;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
int argc = builtin_count_args ( argv ) ;
2007-09-25 16:14:47 +00:00
int mode = BIND_INSERT ;
int res = STATUS_BUILTIN_OK ;
int all = 0 ;
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
int use_terminfo = 0 ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
woptind = 0 ;
2010-10-08 00:43:57 +00:00
static const struct woption
2005-09-20 13:26:39 +00:00
long_options [ ] =
{
{
2007-09-25 16:14:47 +00:00
L " all " , no_argument , 0 , ' a '
}
,
{
L " erase " , no_argument , 0 , ' e '
}
,
{
L " function-names " , no_argument , 0 , ' f '
2005-09-20 13:26:39 +00:00
}
,
2006-05-26 11:24:02 +00:00
{
L " help " , no_argument , 0 , ' h '
}
,
2007-09-25 16:14:47 +00:00
{
L " key " , no_argument , 0 , ' k '
}
,
{
L " key-names " , no_argument , 0 , ' K '
}
,
2006-01-30 19:53:10 +00:00
{
0 , 0 , 0 , 0
2005-09-20 13:26:39 +00:00
}
}
2006-01-30 19:53:10 +00:00
;
2005-09-20 13:26:39 +00:00
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
2007-09-25 16:14:47 +00:00
argv ,
L " aehkKf " ,
long_options ,
& opt_index ) ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
if ( opt = = - 1 )
break ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2005-09-20 13:26:39 +00:00
BUILTIN_ERR_UNKNOWN ,
2006-01-04 12:51:02 +00:00
argv [ 0 ] ,
2006-01-30 19:53:10 +00:00
long_options [ opt_index ] . name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-30 19:53:10 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
2007-09-25 16:14:47 +00:00
case ' a ' :
all = 1 ;
2005-09-20 13:26:39 +00:00
break ;
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
case ' e ' :
mode = BIND_ERASE ;
break ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
2006-05-26 11:24:02 +00:00
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
case ' k ' :
use_terminfo = 1 ;
break ;
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
case ' K ' :
mode = BIND_KEY_NAMES ;
break ;
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
case ' f ' :
mode = BIND_FUNCTION_NAMES ;
break ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
case ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
2011-12-27 03:18:46 +00:00
2006-01-30 19:53:10 +00:00
}
2005-09-20 13:26:39 +00:00
2007-09-25 16:14:47 +00:00
switch ( mode )
2005-09-20 13:26:39 +00:00
{
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
case BIND_ERASE :
{
builtin_bind_erase ( & argv [ woptind ] , all ) ;
break ;
}
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
case BIND_INSERT :
{
switch ( argc - woptind )
{
case 0 :
{
builtin_bind_list ( ) ;
break ;
}
case 2 :
{
builtin_bind_add ( argv [ woptind ] , argv [ woptind + 1 ] , use_terminfo ) ;
break ;
}
2005-09-20 13:26:39 +00:00
2007-09-25 16:14:47 +00:00
default :
{
res = STATUS_BUILTIN_ERROR ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , _ ( L " %ls: Expected zero or two parameters, got %d " ) , argv [ 0 ] , argc - woptind ) ;
2007-09-25 16:14:47 +00:00
break ;
}
}
break ;
}
case BIND_KEY_NAMES :
{
builtin_bind_key_names ( all ) ;
break ;
}
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
case BIND_FUNCTION_NAMES :
{
builtin_bind_function_names ( ) ;
break ;
}
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
default :
{
res = STATUS_BUILTIN_ERROR ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , _ ( L " %ls: Invalid state \n " ) , argv [ 0 ] ) ;
2007-09-25 16:14:47 +00:00
break ;
}
}
2011-12-27 03:18:46 +00:00
2007-09-25 16:14:47 +00:00
return res ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
/**
2006-02-05 21:20:50 +00:00
The block builtin , used for temporarily blocking events
*/
2012-01-16 20:10:08 +00:00
static int builtin_block ( parser_t & parser , wchar_t * * argv )
2005-12-11 22:21:01 +00:00
{
enum
{
UNSET ,
GLOBAL ,
LOCAL ,
}
;
int scope = UNSET ;
int erase = 0 ;
int argc = builtin_count_args ( argv ) ;
2006-01-30 19:53:10 +00:00
int type = ( 1 < < EVENT_ANY ) ;
2005-12-11 22:21:01 +00:00
woptind = 0 ;
2010-10-08 00:43:57 +00:00
static const struct woption
2005-12-11 22:21:01 +00:00
long_options [ ] =
{
{
2006-01-30 19:53:10 +00:00
L " erase " , no_argument , 0 , ' e '
2005-12-11 22:21:01 +00:00
}
,
{
2006-01-30 19:53:10 +00:00
L " local " , no_argument , 0 , ' l '
2005-12-11 22:21:01 +00:00
}
,
{
2006-01-30 19:53:10 +00:00
L " global " , no_argument , 0 , ' g '
2005-12-11 22:21:01 +00:00
}
,
{
2006-01-30 19:53:10 +00:00
L " help " , no_argument , 0 , ' h '
2005-12-11 22:21:01 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
0 , 0 , 0 , 0
2005-12-11 22:21:01 +00:00
}
}
2006-01-30 19:53:10 +00:00
;
2005-12-11 22:21:01 +00:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-30 19:53:10 +00:00
2005-12-11 22:21:01 +00:00
int opt = wgetopt_long ( argc ,
2006-01-30 19:53:10 +00:00
argv ,
L " elgh " ,
long_options ,
2005-12-11 22:21:01 +00:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-30 19:53:10 +00:00
2005-12-11 22:21:01 +00:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
2006-01-30 19:53:10 +00:00
long_options [ opt_index ] . name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-30 19:53:10 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-12-11 22:21:01 +00:00
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2006-01-30 19:53:10 +00:00
2005-12-11 22:21:01 +00:00
case ' g ' :
scope = GLOBAL ;
break ;
2006-01-30 19:53:10 +00:00
2005-12-11 22:21:01 +00:00
case ' l ' :
scope = LOCAL ;
break ;
2006-01-30 19:53:10 +00:00
2005-12-11 22:21:01 +00:00
case ' e ' :
erase = 1 ;
break ;
2006-01-30 19:53:10 +00:00
2005-12-11 22:21:01 +00:00
case ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
2005-12-11 22:21:01 +00:00
}
2006-01-30 19:53:10 +00:00
}
2005-12-11 22:21:01 +00:00
if ( erase )
{
if ( scope ! = UNSET )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , _ ( L " %ls: Can not specify scope when removing block \n " ) , argv [ 0 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-12-11 22:21:01 +00:00
}
2012-02-08 05:04:51 +00:00
if ( parser . global_event_blocks . empty ( ) )
2005-12-11 22:21:01 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , _ ( L " %ls: No blocks defined \n " ) , argv [ 0 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-12-11 22:21:01 +00:00
}
2012-02-08 05:04:51 +00:00
parser . global_event_blocks . pop_front ( ) ;
2005-12-11 22:21:01 +00:00
}
else
{
2012-01-16 20:10:08 +00:00
block_t * block = parser . current_block ;
2006-01-30 19:53:10 +00:00
2012-02-08 05:04:51 +00:00
event_block_t eb = { } ;
eb . typemask = type ;
2005-12-11 22:21:01 +00:00
switch ( scope )
{
case LOCAL :
{
if ( ! block - > outer )
block = 0 ;
break ;
}
case GLOBAL :
{
block = 0 ;
}
case UNSET :
{
2011-12-27 03:18:46 +00:00
while ( block & &
2008-01-09 03:01:36 +00:00
block - > type ! = FUNCTION_CALL & &
block - > type ! = FUNCTION_CALL_NO_SHADOW )
2005-12-11 22:21:01 +00:00
block = block - > outer ;
}
}
if ( block )
{
2012-02-08 05:04:51 +00:00
block - > event_blocks . push_front ( eb ) ;
2005-12-11 22:21:01 +00:00
}
else
{
2012-02-08 05:04:51 +00:00
parser . global_event_blocks . push_front ( eb ) ;
2006-01-30 19:53:10 +00:00
}
2005-12-11 22:21:01 +00:00
}
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2006-01-30 19:53:10 +00:00
2005-12-11 22:21:01 +00:00
}
2005-09-20 13:26:39 +00:00
/**
2007-10-28 09:08:40 +00:00
The builtin builtin , used for giving builtins precedence over
2007-07-31 21:23:32 +00:00
functions . Mostly handled by the parser . All this code does is some
additional operational modes , such as printing a list of all
2007-10-28 09:08:40 +00:00
builtins , printing help , etc .
2005-09-20 13:26:39 +00:00
*/
2012-01-16 20:10:08 +00:00
static int builtin_builtin ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
int argc = builtin_count_args ( argv ) ;
int list = 0 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
woptind = 0 ;
2010-10-08 00:43:57 +00:00
static const struct woption
2005-09-20 13:26:39 +00:00
long_options [ ] =
{
{
2006-01-30 19:53:10 +00:00
L " names " , no_argument , 0 , ' n '
2005-09-20 13:26:39 +00:00
}
,
{
2006-01-30 19:53:10 +00:00
L " help " , no_argument , 0 , ' h '
2005-09-20 13:26:39 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
0 , 0 , 0 , 0
2005-09-20 13:26:39 +00:00
}
}
2006-01-30 19:53:10 +00:00
;
2005-09-20 13:26:39 +00:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
int opt = wgetopt_long ( argc ,
2006-01-30 19:53:10 +00:00
argv ,
L " nh " ,
long_options ,
2005-09-20 13:26:39 +00:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-30 19:53:10 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
case ' n ' :
list = 1 ;
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
case ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
}
2005-09-20 13:26:39 +00:00
if ( list )
{
2012-02-01 03:47:56 +00:00
wcstring_list_t names = builtin_get_names ( ) ;
sort ( names . begin ( ) , names . end ( ) ) ;
2011-12-27 03:18:46 +00:00
2012-02-01 03:47:56 +00:00
for ( size_t i = 0 ; i < names . size ( ) ; i + + )
2005-09-20 13:26:39 +00:00
{
2012-02-01 03:47:56 +00:00
const wchar_t * el = names . at ( i ) . c_str ( ) ;
2011-12-27 03:18:46 +00:00
2012-02-22 18:51:06 +00:00
stdout_buffer . append ( el ) ;
stdout_buffer . append ( L " \n " ) ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
}
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
2008-01-13 16:47:47 +00:00
/**
Implementation of the builtin emit command , used to create events .
*/
2012-01-16 20:10:08 +00:00
static int builtin_emit ( parser_t & parser , wchar_t * * argv )
2007-08-19 16:42:30 +00:00
{
int argc = builtin_count_args ( argv ) ;
2011-12-27 03:18:46 +00:00
2007-08-19 16:42:30 +00:00
woptind = 0 ;
2010-10-08 00:43:57 +00:00
static const struct woption
2007-08-19 16:42:30 +00:00
long_options [ ] =
{
{
L " help " , no_argument , 0 , ' h '
}
,
{
0 , 0 , 0 , 0
}
}
;
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " h " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-08-19 16:42:30 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2007-08-19 16:42:30 +00:00
return STATUS_BUILTIN_ERROR ;
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2007-08-19 16:42:30 +00:00
return STATUS_BUILTIN_OK ;
case ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2007-08-19 16:42:30 +00:00
return STATUS_BUILTIN_ERROR ;
}
}
for ( ; woptind < argc ; woptind + + )
{
event_fire_generic ( argv [ woptind ] ) ;
}
return STATUS_BUILTIN_OK ;
2011-12-27 03:18:46 +00:00
2007-08-19 16:42:30 +00:00
}
2005-09-20 13:26:39 +00:00
/**
A generic bultin that only supports showing a help message . This is
only a placeholder that prints the help message . Useful for
2012-02-01 03:47:56 +00:00
commands that live in the parser .
2005-09-20 13:26:39 +00:00
*/
2012-01-16 20:10:08 +00:00
static int builtin_generic ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
int argc = builtin_count_args ( argv ) ;
woptind = 0 ;
2010-10-08 00:43:57 +00:00
static const struct woption
2005-09-20 13:26:39 +00:00
long_options [ ] =
{
{
L " help " , no_argument , 0 , ' h '
}
,
2006-01-30 19:53:10 +00:00
{
0 , 0 , 0 , 0
2005-09-20 13:26:39 +00:00
}
}
2006-01-30 19:53:10 +00:00
;
2005-09-20 13:26:39 +00:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
int opt = wgetopt_long ( argc ,
2006-01-30 19:53:10 +00:00
argv ,
L " h " ,
long_options ,
2005-09-20 13:26:39 +00:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
case ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
}
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
/**
2006-09-08 14:12:41 +00:00
Output a definition of the specified function to the specified
2012-03-26 05:41:22 +00:00
string . Used by the functions builtin .
2006-01-23 20:40:14 +00:00
*/
2012-02-22 18:51:06 +00:00
static void functions_def ( const wcstring & name , wcstring & out )
2005-12-17 12:25:46 +00:00
{
2012-05-18 02:46:08 +00:00
wcstring desc , def ;
function_get_desc ( name , & desc ) ;
2012-05-18 02:37:46 +00:00
function_get_definition ( name , & def ) ;
2006-01-30 19:53:10 +00:00
2012-02-09 03:02:25 +00:00
event_t search ( EVENT_ANY ) ;
2006-01-23 23:33:47 +00:00
2005-12-17 12:25:46 +00:00
search . function_name = name ;
2006-01-23 23:33:47 +00:00
2012-02-08 01:06:45 +00:00
std : : vector < event_t * > ev ;
2005-12-17 12:25:46 +00:00
event_get ( & search , & ev ) ;
2006-01-23 23:33:47 +00:00
2012-02-22 18:51:06 +00:00
out . append ( L " function " ) ;
out . append ( name ) ;
2005-12-17 12:25:46 +00:00
2012-05-18 02:46:08 +00:00
if ( ! desc . empty ( ) )
2005-12-17 12:25:46 +00:00
{
2012-05-18 02:46:08 +00:00
wcstring esc_desc = escape_string ( desc , true ) ;
2012-02-22 18:51:06 +00:00
out . append ( L " --description " ) ;
2012-05-18 02:46:08 +00:00
out . append ( esc_desc ) ;
2005-12-17 12:25:46 +00:00
}
2006-01-23 23:33:47 +00:00
2007-09-22 22:19:20 +00:00
if ( ! function_get_shadows ( name ) )
{
2012-02-22 18:51:06 +00:00
out . append ( L " --no-scope-shadowing " ) ;
2007-09-22 22:19:20 +00:00
}
2012-02-08 01:06:45 +00:00
for ( size_t i = 0 ; i < ev . size ( ) ; i + + )
2005-12-17 12:25:46 +00:00
{
2012-02-08 01:06:45 +00:00
event_t * next = ev . at ( i ) ;
2005-12-17 12:25:46 +00:00
switch ( next - > type )
{
case EVENT_SIGNAL :
{
2012-02-22 18:51:06 +00:00
append_format ( out , L " --on-signal %ls " , sig2wcs ( next - > param1 . signal ) ) ;
2005-12-17 12:25:46 +00:00
break ;
}
2006-01-23 23:33:47 +00:00
2005-12-17 12:25:46 +00:00
case EVENT_VARIABLE :
{
2012-02-22 18:51:06 +00:00
append_format ( out , L " --on-variable %ls " , next - > str_param1 . c_str ( ) ) ;
2005-12-17 12:25:46 +00:00
break ;
}
case EVENT_EXIT :
{
if ( next - > param1 . pid > 0 )
2012-02-22 18:51:06 +00:00
append_format ( out , L " --on-process-exit %d " , next - > param1 . pid ) ;
2005-12-17 12:25:46 +00:00
else
2012-02-22 18:51:06 +00:00
append_format ( out , L " --on-job-exit %d " , - next - > param1 . pid ) ;
2005-12-17 12:25:46 +00:00
break ;
}
case EVENT_JOB_ID :
{
2012-02-28 02:43:24 +00:00
const job_t * j = job_get ( next - > param1 . job_id ) ;
2005-12-17 12:25:46 +00:00
if ( j )
2012-02-22 18:51:06 +00:00
append_format ( out , L " --on-job-exit %d " , j - > pgid ) ;
2005-12-17 12:25:46 +00:00
break ;
}
2007-08-19 16:42:30 +00:00
case EVENT_GENERIC :
{
2012-02-22 18:51:06 +00:00
append_format ( out , L " --on-event %ls " , next - > str_param1 . c_str ( ) ) ;
2007-08-19 16:42:30 +00:00
break ;
}
2011-12-27 03:18:46 +00:00
2005-12-17 12:25:46 +00:00
}
2006-01-30 19:53:10 +00:00
2006-01-23 23:33:47 +00:00
}
2011-12-27 03:18:46 +00:00
2012-01-14 07:44:18 +00:00
wcstring_list_t named = function_get_named_arguments ( name ) ;
if ( named . size ( ) > 0 )
2007-04-22 21:15:34 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( out , L " --argument " ) ;
2012-02-08 01:06:45 +00:00
for ( size_t i = 0 ; i < named . size ( ) ; i + + )
2007-04-22 21:15:34 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( out , L " %ls " , named . at ( i ) . c_str ( ) ) ;
2007-04-22 21:15:34 +00:00
}
}
2011-12-27 03:18:46 +00:00
2012-03-26 05:41:22 +00:00
/* This forced tab is sort of crummy - not all functions start with a tab */
2012-05-18 02:37:46 +00:00
append_format ( out , L " \n \t %ls " , def . c_str ( ) ) ;
2012-03-26 05:41:22 +00:00
2012-03-26 06:31:03 +00:00
/* Append a newline before the 'end', unless there already is one there */
2012-05-18 02:37:46 +00:00
if ( ! string_suffixes_string ( L " \n " , def ) ) {
2012-03-26 05:41:22 +00:00
out . push_back ( L ' \n ' ) ;
}
out . append ( L " end \n " ) ;
2005-12-17 12:25:46 +00:00
}
2005-09-20 13:26:39 +00:00
/**
The functions builtin , used for listing and erasing functions .
*/
2012-01-16 20:10:08 +00:00
static int builtin_functions ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
int i ;
int erase = 0 ;
2006-01-30 19:53:10 +00:00
wchar_t * desc = 0 ;
2005-09-20 13:26:39 +00:00
int argc = builtin_count_args ( argv ) ;
int list = 0 ;
2006-01-30 19:53:10 +00:00
int show_hidden = 0 ;
2006-12-13 14:34:31 +00:00
int res = STATUS_BUILTIN_OK ;
2006-07-12 17:46:55 +00:00
int query = 0 ;
2010-09-09 13:48:18 +00:00
int copy = 0 ;
2006-01-23 23:33:47 +00:00
2005-09-20 13:26:39 +00:00
woptind = 0 ;
2010-10-08 00:43:57 +00:00
static const struct woption
2005-09-20 13:26:39 +00:00
long_options [ ] =
{
{
2006-01-30 19:53:10 +00:00
L " erase " , no_argument , 0 , ' e '
2005-09-20 13:26:39 +00:00
}
,
{
2006-01-30 19:53:10 +00:00
L " description " , required_argument , 0 , ' d '
2005-09-20 13:26:39 +00:00
}
,
{
2006-01-30 19:53:10 +00:00
L " names " , no_argument , 0 , ' n '
2005-09-20 13:26:39 +00:00
}
,
{
L " all " , no_argument , 0 , ' a '
}
,
2006-05-26 11:24:02 +00:00
{
L " help " , no_argument , 0 , ' h '
}
,
2006-07-12 17:46:55 +00:00
{
L " query " , no_argument , 0 , ' q '
}
,
2010-09-07 17:31:05 +00:00
{
2010-09-09 13:48:18 +00:00
L " copy " , no_argument , 0 , ' c '
2010-09-07 17:31:05 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
0 , 0 , 0 , 0
2005-09-20 13:26:39 +00:00
}
}
2006-01-30 19:53:10 +00:00
;
2005-09-20 13:26:39 +00:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-23 23:33:47 +00:00
2005-09-20 13:26:39 +00:00
int opt = wgetopt_long ( argc ,
2006-01-30 19:53:10 +00:00
argv ,
2010-09-09 13:48:18 +00:00
L " ed:nahqc " ,
2006-01-30 19:53:10 +00:00
long_options ,
2005-09-20 13:26:39 +00:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-23 23:33:47 +00:00
2005-09-20 13:26:39 +00:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2011-12-27 03:18:46 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-30 19:53:10 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
case ' e ' :
erase = 1 ;
2005-09-20 13:26:39 +00:00
break ;
case ' d ' :
desc = woptarg ;
2006-01-30 19:53:10 +00:00
break ;
2005-09-20 13:26:39 +00:00
case ' n ' :
list = 1 ;
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
case ' a ' :
show_hidden = 1 ;
break ;
2006-01-30 19:53:10 +00:00
2006-05-26 11:24:02 +00:00
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2006-05-26 11:24:02 +00:00
2006-07-12 17:46:55 +00:00
case ' q ' :
query = 1 ;
break ;
2010-09-09 13:48:18 +00:00
case ' c ' :
copy = 1 ;
2010-09-07 17:31:05 +00:00
break ;
2005-09-20 13:26:39 +00:00
case ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
2006-01-23 23:33:47 +00:00
}
2005-09-20 13:26:39 +00:00
/*
2010-09-09 13:48:18 +00:00
Erase , desc , query , copy and list are mutually exclusive
2005-09-20 13:26:39 +00:00
*/
2010-09-09 13:48:18 +00:00
if ( ( erase + ( ! ! desc ) + list + query + copy ) > 1 )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Invalid combination of options \n " ) ,
argv [ 0 ] ) ;
2006-01-23 23:33:47 +00:00
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-23 23:33:47 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
if ( erase )
{
int i ;
for ( i = woptind ; i < argc ; i + + )
function_remove ( argv [ i ] ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
else if ( desc )
{
wchar_t * func ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( argc - woptind ! = 1 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Expected exactly one function name \n " ) ,
2006-01-30 19:53:10 +00:00
argv [ 0 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-30 19:53:10 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
func = argv [ woptind ] ;
if ( ! function_exists ( func ) )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Function '%ls' does not exist \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
func ) ;
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-30 19:53:10 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
function_set_desc ( func , desc ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
2006-12-13 14:21:07 +00:00
else if ( list | | ( argc = = woptind ) )
2005-09-20 13:26:39 +00:00
{
2006-01-15 11:58:05 +00:00
int is_screen = ! builtin_out_redirect & & isatty ( 1 ) ;
2012-01-14 07:44:18 +00:00
size_t i ;
wcstring_list_t names = function_get_names ( show_hidden ) ;
std : : sort ( names . begin ( ) , names . end ( ) ) ;
2006-01-15 11:58:05 +00:00
if ( is_screen )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
wcstring buff ;
2006-01-30 19:53:10 +00:00
2012-01-14 07:44:18 +00:00
for ( i = 0 ; i < names . size ( ) ; i + + )
2006-01-15 11:58:05 +00:00
{
2012-02-22 18:51:06 +00:00
buff . append ( names . at ( i ) ) ;
buff . append ( L " , " ) ;
2006-01-15 11:58:05 +00:00
}
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
write_screen ( buff , stdout_buffer ) ;
2006-01-15 11:58:05 +00:00
}
else
{
2012-01-14 07:44:18 +00:00
for ( i = 0 ; i < names . size ( ) ; i + + )
2006-01-15 11:58:05 +00:00
{
2012-02-22 18:51:06 +00:00
stdout_buffer . append ( names . at ( i ) . c_str ( ) ) ;
stdout_buffer . append ( L " \n " ) ;
2006-01-15 11:58:05 +00:00
}
2005-09-20 13:26:39 +00:00
}
2006-01-24 18:14:10 +00:00
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
2010-09-09 13:48:18 +00:00
else if ( copy )
2010-09-07 17:31:05 +00:00
{
2012-02-19 17:25:15 +00:00
wcstring current_func ;
wcstring new_func ;
2010-09-07 17:31:05 +00:00
if ( argc - woptind ! = 2 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2010-09-07 17:31:05 +00:00
_ ( L " %ls: Expected exactly two names (current function name, and new function name) \n " ) ,
argv [ 0 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2010-09-07 17:31:05 +00:00
return STATUS_BUILTIN_ERROR ;
}
current_func = argv [ woptind ] ;
new_func = argv [ woptind + 1 ] ;
if ( ! function_exists ( current_func ) )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2010-09-07 17:31:05 +00:00
_ ( L " %ls: Function '%ls' does not exist \n " ) ,
argv [ 0 ] ,
2012-02-19 17:25:15 +00:00
current_func . c_str ( ) ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2010-09-07 17:31:05 +00:00
return STATUS_BUILTIN_ERROR ;
2010-09-12 03:16:11 +00:00
}
2012-02-19 17:25:15 +00:00
if ( ( wcsfuncname ( new_func . c_str ( ) ) ! = 0 ) | | parser_keywords_is_reserved ( new_func ) )
2010-09-12 03:16:11 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2010-09-12 03:16:11 +00:00
_ ( L " %ls: Illegal function name '%ls' \n " ) ,
argv [ 0 ] ,
2012-02-19 17:25:15 +00:00
new_func . c_str ( ) ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2010-09-12 03:16:11 +00:00
return STATUS_BUILTIN_ERROR ;
2010-09-07 17:31:05 +00:00
}
2010-09-09 13:48:18 +00:00
// keep things simple: don't allow existing names to be copy targets.
2010-09-07 17:31:05 +00:00
if ( function_exists ( new_func ) )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2010-09-09 13:48:18 +00:00
_ ( L " %ls: Function '%ls' already exists. Cannot create copy '%ls' \n " ) ,
2010-09-07 17:31:05 +00:00
argv [ 0 ] ,
2012-02-19 17:25:15 +00:00
new_func . c_str ( ) ,
current_func . c_str ( ) ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2010-09-07 17:31:05 +00:00
return STATUS_BUILTIN_ERROR ;
}
2010-09-09 13:48:18 +00:00
if ( function_copy ( current_func , new_func ) )
return STATUS_BUILTIN_OK ;
return STATUS_BUILTIN_ERROR ;
2010-09-07 17:31:05 +00:00
}
2006-01-30 19:53:10 +00:00
2006-12-13 14:21:07 +00:00
for ( i = woptind ; i < argc ; i + + )
2005-09-20 13:26:39 +00:00
{
2006-12-13 14:21:07 +00:00
if ( ! function_exists ( argv [ i ] ) )
res + + ;
else
2005-09-20 13:26:39 +00:00
{
2006-07-12 17:46:55 +00:00
if ( ! query )
2005-09-20 13:26:39 +00:00
{
2007-04-22 18:56:27 +00:00
if ( i ! = woptind )
2012-02-22 18:51:06 +00:00
stdout_buffer . append ( L " \n " ) ;
2011-12-27 03:18:46 +00:00
2012-02-22 18:51:06 +00:00
functions_def ( argv [ i ] , stdout_buffer ) ;
2005-10-15 00:51:26 +00:00
}
2011-12-27 03:18:46 +00:00
}
2005-09-20 13:26:39 +00:00
}
2006-12-13 14:21:07 +00:00
2005-10-15 00:51:26 +00:00
return res ;
2012-03-07 19:35:22 +00:00
}
/** The echo builtin.
2012-05-19 23:59:56 +00:00
bash only respects - n if it ' s the first argument . We ' ll do the same .
We also support a new option - s to mean " no spaces "
*/
2006-01-30 19:53:10 +00:00
2012-03-07 19:35:22 +00:00
static int builtin_echo ( parser_t & parser , wchar_t * * argv )
{
/* Skip first arg */
if ( ! * argv + + )
return STATUS_BUILTIN_ERROR ;
2012-05-19 23:59:56 +00:00
/* Process options */
bool print_newline = true , print_spaces = true ;
while ( * argv ) {
if ( ! wcscmp ( * argv , L " -n " ) ) {
print_newline = false ;
argv + + ;
} else if ( ! wcscmp ( * argv , L " -s " ) ) {
print_spaces = false ;
argv + + ;
} else {
break ;
}
2012-03-07 19:35:22 +00:00
}
2012-05-19 23:59:56 +00:00
2012-03-07 19:35:22 +00:00
for ( size_t idx = 0 ; argv [ idx ] ; idx + + ) {
2012-05-19 23:59:56 +00:00
if ( print_spaces & & idx > 0 )
2012-03-07 19:35:22 +00:00
stdout_buffer . push_back ( ' ' ) ;
stdout_buffer . append ( argv [ idx ] ) ;
}
2012-05-19 23:59:56 +00:00
if ( print_newline )
2012-03-07 19:35:22 +00:00
stdout_buffer . push_back ( ' \n ' ) ;
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
2012-03-10 04:16:26 +00:00
/** The pwd builtin. We don't respect -P to resolve symbolic links because we try to always resolve them. */
static int builtin_pwd ( parser_t & parser , wchar_t * * argv )
{
wchar_t dir_path [ 4096 ] ;
wchar_t * res = wgetcwd ( dir_path , 4096 ) ;
if ( res = = NULL ) {
return STATUS_BUILTIN_ERROR ;
} else {
stdout_buffer . append ( dir_path ) ;
stdout_buffer . push_back ( L ' \n ' ) ;
return STATUS_BUILTIN_OK ;
}
}
2005-10-15 00:51:26 +00:00
2005-09-20 13:26:39 +00:00
/**
The function builtin , used for providing subroutines .
It calls various functions from function . c to perform any heavy lifting .
*/
2012-01-16 20:10:08 +00:00
static int builtin_function ( parser_t & parser , wchar_t * * argv )
2006-01-30 19:53:10 +00:00
{
2005-09-20 13:26:39 +00:00
int argc = builtin_count_args ( argv ) ;
2006-12-13 14:34:31 +00:00
int res = STATUS_BUILTIN_OK ;
2006-01-30 19:53:10 +00:00
wchar_t * desc = 0 ;
2012-02-09 03:02:25 +00:00
std : : vector < event_t > events ;
2012-02-09 07:53:23 +00:00
std : : auto_ptr < wcstring_list_t > named_arguments ( NULL ) ;
2007-04-16 20:06:11 +00:00
wchar_t * name = 0 ;
2007-04-22 22:10:33 +00:00
int shadows = 1 ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
woptind = 0 ;
2012-01-16 20:10:08 +00:00
parser . push_block ( FUNCTION_DEF ) ;
2006-02-06 18:11:01 +00:00
2010-10-08 00:43:57 +00:00
static const struct woption
2005-09-20 13:26:39 +00:00
long_options [ ] =
{
{
2006-01-30 19:53:10 +00:00
L " description " , required_argument , 0 , ' d '
2005-09-20 13:26:39 +00:00
}
,
2005-10-05 22:37:08 +00:00
{
2006-01-30 19:53:10 +00:00
L " on-signal " , required_argument , 0 , ' s '
2005-10-05 22:37:08 +00:00
}
,
{
2006-01-30 19:53:10 +00:00
L " on-job-exit " , required_argument , 0 , ' j '
2005-10-11 19:23:43 +00:00
}
,
{
2006-01-30 19:53:10 +00:00
L " on-process-exit " , required_argument , 0 , ' p '
2005-10-05 22:37:08 +00:00
}
,
{
2006-01-30 19:53:10 +00:00
L " on-variable " , required_argument , 0 , ' v '
2005-10-05 22:37:08 +00:00
}
,
2007-08-19 16:42:30 +00:00
{
L " on-event " , required_argument , 0 , ' e '
}
,
2006-05-26 11:24:02 +00:00
{
L " help " , no_argument , 0 , ' h '
}
,
2007-04-16 20:06:11 +00:00
{
L " argument-names " , no_argument , 0 , ' a '
}
,
2007-04-22 22:10:33 +00:00
{
L " no-scope-shadowing " , no_argument , 0 , ' S '
}
,
2006-01-30 19:53:10 +00:00
{
0 , 0 , 0 , 0
2005-09-20 13:26:39 +00:00
}
}
2006-01-30 19:53:10 +00:00
;
2005-10-05 22:37:08 +00:00
while ( 1 & & ( ! res ) )
2005-09-20 13:26:39 +00:00
{
int opt_index = 0 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
int opt = wgetopt_long ( argc ,
2007-08-19 16:42:30 +00:00
argv ,
L " d:s:j:p:v:e:haS " ,
long_options ,
& opt_index ) ;
2005-09-20 13:26:39 +00:00
if ( opt = = - 1 )
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2006-01-24 18:14:10 +00:00
2005-10-05 22:37:08 +00:00
res = 1 ;
2006-01-30 19:53:10 +00:00
break ;
case ' d ' :
desc = woptarg ;
2005-09-20 13:26:39 +00:00
break ;
2005-10-05 22:37:08 +00:00
case ' s ' :
{
2005-10-06 11:54:16 +00:00
int sig = wcs2sig ( woptarg ) ;
2006-01-30 19:53:10 +00:00
2005-10-06 11:54:16 +00:00
if ( sig < 0 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Unknown signal '%ls' \n " ) ,
2005-10-06 11:54:16 +00:00
argv [ 0 ] ,
woptarg ) ;
res = 1 ;
break ;
}
2012-02-09 03:02:25 +00:00
events . push_back ( event_t : : signal_event ( sig ) ) ;
2006-01-30 19:53:10 +00:00
break ;
2005-10-05 22:37:08 +00:00
}
2006-01-30 19:53:10 +00:00
2005-10-05 22:37:08 +00:00
case ' v ' :
{
2006-04-21 14:29:39 +00:00
if ( wcsvarname ( woptarg ) )
2005-10-06 11:54:16 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Invalid variable name '%ls' \n " ) ,
2005-10-06 11:54:16 +00:00
argv [ 0 ] ,
woptarg ) ;
2007-04-22 21:15:34 +00:00
res = STATUS_BUILTIN_ERROR ;
2005-10-06 11:54:16 +00:00
break ;
}
2006-01-30 19:53:10 +00:00
2012-02-09 03:02:25 +00:00
events . push_back ( event_t : : variable_event ( woptarg ) ) ;
2005-10-05 22:37:08 +00:00
break ;
}
2006-01-30 19:53:10 +00:00
2007-08-19 16:42:30 +00:00
case ' e ' :
{
2012-02-09 03:02:25 +00:00
events . push_back ( event_t : : generic_event ( woptarg ) ) ;
2007-08-19 16:42:30 +00:00
break ;
}
2005-10-11 19:23:43 +00:00
case ' j ' :
case ' p ' :
2005-10-05 22:37:08 +00:00
{
2005-10-06 11:54:16 +00:00
pid_t pid ;
wchar_t * end ;
2012-02-09 03:02:25 +00:00
event_t e ( EVENT_ANY ) ;
2011-12-27 03:18:46 +00:00
2006-01-30 19:53:10 +00:00
if ( ( opt = = ' j ' ) & &
2005-10-15 00:51:26 +00:00
( wcscasecmp ( woptarg , L " caller " ) = = 0 ) )
{
int job_id = - 1 ;
2006-01-30 19:53:10 +00:00
if ( is_subshell )
2005-10-15 00:51:26 +00:00
{
2012-01-16 20:10:08 +00:00
block_t * b = parser . current_block ;
2006-01-30 19:53:10 +00:00
2005-10-15 00:51:26 +00:00
while ( b & & ( b - > type ! = SUBST ) )
b = b - > outer ;
2006-01-30 19:53:10 +00:00
2005-10-15 00:51:26 +00:00
if ( b )
{
b = b - > outer ;
}
if ( b - > job )
{
job_id = b - > job - > job_id ;
}
}
2006-01-30 19:53:10 +00:00
2005-10-15 00:51:26 +00:00
if ( job_id = = - 1 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Cannot find calling job for event handler \n " ) ,
2005-10-15 00:51:26 +00:00
argv [ 0 ] ) ;
res = 1 ;
}
else
{
2012-02-09 03:02:25 +00:00
e . type = EVENT_JOB_ID ;
e . param1 . job_id = job_id ;
2005-10-15 00:51:26 +00:00
}
2006-01-30 19:53:10 +00:00
2005-10-15 00:51:26 +00:00
}
else
{
errno = 0 ;
2006-01-30 19:53:10 +00:00
pid = wcstol ( woptarg , & end , 10 ) ;
2005-10-15 00:51:26 +00:00
if ( errno | | ! end | | * end )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Invalid process id %ls \n " ) ,
2005-10-15 00:51:26 +00:00
argv [ 0 ] ,
woptarg ) ;
res = 1 ;
break ;
2006-01-30 19:53:10 +00:00
}
2012-02-09 03:02:25 +00:00
e . type = EVENT_EXIT ;
e . param1 . pid = ( opt = = ' j ' ? - 1 : 1 ) * abs ( pid ) ;
2005-10-15 00:51:26 +00:00
}
if ( res )
{
2012-02-09 03:02:25 +00:00
/* nothing */
2005-10-15 00:51:26 +00:00
}
else
{
2012-02-08 10:34:31 +00:00
events . push_back ( e ) ;
2005-10-15 00:51:26 +00:00
}
2006-01-30 19:53:10 +00:00
break ;
2005-10-05 22:37:08 +00:00
}
2006-01-30 19:53:10 +00:00
2007-04-16 20:06:11 +00:00
case ' a ' :
2012-02-09 07:53:23 +00:00
if ( named_arguments . get ( ) = = NULL )
named_arguments . reset ( new wcstring_list_t ) ;
2007-04-16 20:06:11 +00:00
break ;
2011-12-27 03:18:46 +00:00
2007-04-22 22:10:33 +00:00
case ' S ' :
shadows = 0 ;
break ;
2011-12-27 03:18:46 +00:00
2006-05-26 11:24:02 +00:00
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
case ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2006-01-30 19:53:10 +00:00
res = 1 ;
2005-10-05 22:37:08 +00:00
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
}
2005-10-05 22:37:08 +00:00
if ( ! res )
2006-01-30 19:53:10 +00:00
{
2011-12-27 03:18:46 +00:00
2007-04-16 20:06:11 +00:00
if ( argc = = woptind )
2005-10-05 22:37:08 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-04-16 20:06:11 +00:00
_ ( L " %ls: Expected function name \n " ) ,
argv [ 0 ] ) ;
2005-10-05 22:37:08 +00:00
res = 1 ;
}
2006-10-19 15:47:47 +00:00
else if ( wcsfuncname ( argv [ woptind ] ) )
2006-01-30 19:53:10 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-30 19:53:10 +00:00
_ ( L " %ls: Illegal function name '%ls' \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ woptind ] ) ;
2006-01-30 19:53:10 +00:00
res = 1 ;
}
2007-04-22 09:50:26 +00:00
else if ( parser_keywords_is_reserved ( argv [ woptind ] ) )
2005-10-05 22:37:08 +00:00
{
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: The name '%ls' is reserved, \n and can not be used as a function name \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ woptind ] ) ;
2006-01-30 19:53:10 +00:00
2005-10-05 22:37:08 +00:00
res = 1 ;
}
2007-04-16 20:06:11 +00:00
else
{
name = argv [ woptind + + ] ;
2011-12-27 03:18:46 +00:00
2012-02-09 07:53:23 +00:00
if ( named_arguments . get ( ) )
2007-04-16 20:06:11 +00:00
{
while ( woptind < argc )
{
2007-04-22 21:16:24 +00:00
if ( wcsvarname ( argv [ woptind ] ) )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-04-22 21:16:24 +00:00
_ ( L " %ls: Invalid variable name '%ls' \n " ) ,
argv [ 0 ] ,
argv [ woptind ] ) ;
res = STATUS_BUILTIN_ERROR ;
break ;
}
2011-12-27 03:18:46 +00:00
2012-02-09 07:53:23 +00:00
named_arguments - > push_back ( argv [ woptind + + ] ) ;
2007-04-16 20:06:11 +00:00
}
}
else if ( woptind ! = argc )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-04-16 20:06:11 +00:00
_ ( L " %ls: Expected one argument, got %d \n " ) ,
argv [ 0 ] ,
argc ) ;
res = 1 ;
2011-12-27 03:18:46 +00:00
2007-04-16 20:06:11 +00:00
}
}
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( res )
{
2012-01-14 07:44:18 +00:00
size_t i ;
2005-09-20 13:26:39 +00:00
int chars = 0 ;
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-04 12:51:02 +00:00
const wchar_t * cfa = _ ( L " Current functions are: " ) ;
2012-02-22 18:51:06 +00:00
stderr_buffer . append ( cfa ) ;
2006-01-04 12:51:02 +00:00
chars + = wcslen ( cfa ) ;
2012-01-14 07:44:18 +00:00
wcstring_list_t names = function_get_names ( 0 ) ;
sort ( names . begin ( ) , names . end ( ) ) ;
2006-05-14 09:47:21 +00:00
2012-01-14 07:44:18 +00:00
for ( i = 0 ; i < names . size ( ) ; i + + )
2005-09-20 13:26:39 +00:00
{
2012-01-14 07:44:18 +00:00
const wchar_t * nxt = names . at ( i ) . c_str ( ) ;
2005-09-20 13:26:39 +00:00
int l = wcslen ( nxt + 2 ) ;
2005-10-14 11:40:33 +00:00
if ( chars + l > common_get_width ( ) )
2005-09-20 13:26:39 +00:00
{
chars = 0 ;
2012-02-22 18:51:06 +00:00
stderr_buffer . push_back ( L ' \n ' ) ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
stderr_buffer . append ( nxt ) ;
stderr_buffer . append ( L " " ) ;
2005-09-20 13:26:39 +00:00
}
2012-02-22 18:51:06 +00:00
stderr_buffer . push_back ( L ' \n ' ) ;
2005-09-20 13:26:39 +00:00
2012-01-16 20:10:08 +00:00
parser . pop_block ( ) ;
parser . push_block ( FAKE ) ;
2005-09-20 13:26:39 +00:00
}
else
{
2012-02-08 06:10:35 +00:00
function_data_t * d = new function_data_t ( ) ;
2011-12-27 03:18:46 +00:00
2012-02-09 10:01:49 +00:00
d - > name = name ;
if ( desc )
d - > description = desc ;
2012-02-09 03:02:25 +00:00
d - > events . swap ( events ) ;
2007-04-22 22:10:33 +00:00
d - > shadows = shadows ;
2012-02-09 07:53:23 +00:00
if ( named_arguments . get ( ) )
d - > named_arguments . swap ( * named_arguments ) ;
2011-12-27 03:18:46 +00:00
2012-02-09 03:02:25 +00:00
for ( size_t i = 0 ; i < d - > events . size ( ) ; i + + )
2005-10-05 22:37:08 +00:00
{
2012-02-09 03:02:25 +00:00
event_t & e = d - > events . at ( i ) ;
e . function_name = d - > name ;
2005-10-05 22:37:08 +00:00
}
2006-09-08 14:12:41 +00:00
2012-02-08 06:10:35 +00:00
parser . current_block - > function_data . reset ( d ) ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
}
2011-12-27 03:18:46 +00:00
2012-01-16 20:10:08 +00:00
parser . current_block - > tok_pos = parser . get_pos ( ) ;
parser . current_block - > skip = 1 ;
2006-01-30 19:53:10 +00:00
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
/**
2006-02-05 21:20:50 +00:00
The random builtin . For generating random numbers .
2005-09-20 13:26:39 +00:00
*/
2012-01-16 20:10:08 +00:00
static int builtin_random ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2006-01-30 19:53:10 +00:00
static int seeded = 0 ;
2006-06-15 10:35:56 +00:00
static struct drand48_data seed_buffer ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
int argc = builtin_count_args ( argv ) ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
woptind = 0 ;
2006-01-30 19:53:10 +00:00
2010-10-08 00:43:57 +00:00
static const struct woption
2005-09-20 13:26:39 +00:00
long_options [ ] =
{
{
2006-01-30 19:53:10 +00:00
L " help " , no_argument , 0 , ' h '
2005-09-20 13:26:39 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
0 , 0 , 0 , 0
2005-09-20 13:26:39 +00:00
}
}
2006-01-30 19:53:10 +00:00
;
2005-09-20 13:26:39 +00:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
int opt = wgetopt_long ( argc ,
2006-01-30 19:53:10 +00:00
argv ,
L " h " ,
long_options ,
2005-09-20 13:26:39 +00:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-30 19:53:10 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2005-09-20 13:26:39 +00:00
break ;
case ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
}
2005-09-20 13:26:39 +00:00
switch ( argc - woptind )
{
case 0 :
{
2006-06-15 10:35:56 +00:00
long res ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
if ( ! seeded )
{
seeded = 1 ;
2006-06-15 10:35:56 +00:00
srand48_r ( time ( 0 ) , & seed_buffer ) ;
2005-09-20 13:26:39 +00:00
}
2006-06-15 10:35:56 +00:00
lrand48_r ( & seed_buffer , & res ) ;
2011-12-27 03:18:46 +00:00
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , L " %d \n " , abs ( res % 32767 ) ) ;
2005-09-20 13:26:39 +00:00
break ;
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
case 1 :
{
2006-06-15 10:35:56 +00:00
long foo ;
2005-09-20 13:26:39 +00:00
wchar_t * end = 0 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
errno = 0 ;
foo = wcstol ( argv [ woptind ] , & end , 10 ) ;
if ( errno | | * end )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-30 19:53:10 +00:00
_ ( L " %ls: Seed value '%ls' is not a valid number \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ woptind ] ) ;
2006-01-30 19:53:10 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
seeded = 1 ;
2006-06-15 10:35:56 +00:00
srand48_r ( foo , & seed_buffer ) ;
2005-09-20 13:26:39 +00:00
break ;
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
default :
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Expected zero or one argument, got %d \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
2005-09-20 13:26:39 +00:00
argc - woptind ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
}
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
/**
The read builtin . Reads from stdin and stores the values in environment variables .
*/
2012-01-16 20:10:08 +00:00
static int builtin_read ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
wchar_t * buff = 0 ;
int i , argc = builtin_count_args ( argv ) ;
int place = ENV_USER ;
wchar_t * nxt ;
2011-12-27 03:18:46 +00:00
const wchar_t * prompt = DEFAULT_READ_PROMPT ;
const wchar_t * commandline = L " " ;
2007-01-15 17:53:46 +00:00
int exit_res = STATUS_BUILTIN_OK ;
2011-12-27 03:18:46 +00:00
const wchar_t * mode_name = READ_MODE_NAME ;
2007-01-29 16:26:24 +00:00
int shell = 0 ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
woptind = 0 ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
while ( 1 )
{
2010-10-08 00:43:57 +00:00
static const struct woption
2005-09-20 13:26:39 +00:00
long_options [ ] =
{
{
L " export " , no_argument , 0 , ' x '
}
,
{
L " global " , no_argument , 0 , ' g '
}
,
{
L " local " , no_argument , 0 , ' l '
}
,
2006-01-11 12:26:40 +00:00
{
L " universal " , no_argument , 0 , ' U '
}
,
2005-09-20 13:26:39 +00:00
{
L " unexport " , no_argument , 0 , ' u '
}
,
{
L " prompt " , required_argument , 0 , ' p '
}
,
{
L " command " , required_argument , 0 , ' c '
}
,
2007-01-06 14:24:30 +00:00
{
L " mode-name " , required_argument , 0 , ' m '
}
,
2007-01-29 16:26:24 +00:00
{
2010-11-25 11:09:31 +00:00
L " shell " , no_argument , 0 , ' s '
2007-01-29 16:26:24 +00:00
}
,
2006-05-26 11:24:02 +00:00
{
L " help " , no_argument , 0 , ' h '
}
,
2006-01-30 19:53:10 +00:00
{
0 , 0 , 0 , 0
2005-09-20 13:26:39 +00:00
}
}
2006-01-30 19:53:10 +00:00
;
2005-09-20 13:26:39 +00:00
int opt_index = 0 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
int opt = wgetopt_long ( argc ,
2006-01-30 19:53:10 +00:00
argv ,
2007-01-29 16:26:24 +00:00
L " xglUup:c:hm:s " ,
2006-01-30 19:53:10 +00:00
long_options ,
2005-09-20 13:26:39 +00:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2005-09-20 13:26:39 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
case L ' x ' :
2005-09-20 13:26:39 +00:00
place | = ENV_EXPORT ;
break ;
2007-01-06 14:24:30 +00:00
2006-01-30 19:53:10 +00:00
case L ' g ' :
2005-09-20 13:26:39 +00:00
place | = ENV_GLOBAL ;
break ;
2007-01-06 14:24:30 +00:00
2006-01-30 19:53:10 +00:00
case L ' l ' :
2005-09-20 13:26:39 +00:00
place | = ENV_LOCAL ;
break ;
2007-01-06 14:24:30 +00:00
2006-01-30 19:53:10 +00:00
case L ' U ' :
2006-01-11 12:26:40 +00:00
place | = ENV_UNIVERSAL ;
break ;
2007-01-06 14:24:30 +00:00
2006-01-30 19:53:10 +00:00
case L ' u ' :
2005-09-20 13:26:39 +00:00
place | = ENV_UNEXPORT ;
break ;
2007-01-06 14:24:30 +00:00
2005-09-20 13:26:39 +00:00
case L ' p ' :
prompt = woptarg ;
break ;
2007-01-06 14:24:30 +00:00
2005-09-20 13:26:39 +00:00
case L ' c ' :
commandline = woptarg ;
break ;
2006-01-30 19:53:10 +00:00
2007-01-06 14:24:30 +00:00
case L ' m ' :
mode_name = woptarg ;
break ;
2007-01-29 16:26:24 +00:00
case ' s ' :
shell = 1 ;
break ;
2011-12-27 03:18:46 +00:00
2006-05-26 11:24:02 +00:00
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2006-05-26 11:24:02 +00:00
2005-09-20 13:26:39 +00:00
case L ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
}
2005-09-20 13:26:39 +00:00
if ( ( place & ENV_UNEXPORT ) & & ( place & ENV_EXPORT ) )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
BUILTIN_ERR_EXPUNEXP ,
2007-01-31 16:03:17 +00:00
argv [ 0 ] ) ;
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2006-01-11 12:26:40 +00:00
if ( ( place & ENV_LOCAL ? 1 : 0 ) + ( place & ENV_GLOBAL ? 1 : 0 ) + ( place & ENV_UNIVERSAL ? 1 : 0 ) > 1 )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
BUILTIN_ERR_GLOCAL ,
2007-01-31 16:03:17 +00:00
argv [ 0 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-30 19:53:10 +00:00
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
/*
2006-02-05 21:20:50 +00:00
Verify all variable names
2005-12-07 16:06:47 +00:00
*/
for ( i = woptind ; i < argc ; i + + )
{
wchar_t * src ;
2006-01-30 19:53:10 +00:00
2005-12-07 16:06:47 +00:00
if ( ! wcslen ( argv [ i ] ) )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , BUILTIN_ERR_VARNAME_ZERO , argv [ 0 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-12-07 16:06:47 +00:00
}
2006-01-30 19:53:10 +00:00
2005-12-07 16:06:47 +00:00
for ( src = argv [ i ] ; * src ; src + + )
{
if ( ( ! iswalnum ( * src ) ) & & ( * src ! = L ' _ ' ) )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , BUILTIN_ERR_VARCHAR , argv [ 0 ] , * src ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-12-07 16:06:47 +00:00
}
}
2006-01-30 19:53:10 +00:00
2005-12-07 16:06:47 +00:00
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
/*
The call to reader_readline may change woptind , so we save it away here
*/
i = woptind ;
/*
Check if we should read interactively using \ c reader_readline ( )
*/
2010-11-22 00:43:21 +00:00
if ( isatty ( 0 ) & & builtin_stdin = = 0 )
2006-01-30 19:53:10 +00:00
{
2012-02-06 08:57:43 +00:00
const wchar_t * line ;
2011-12-27 03:18:46 +00:00
2007-01-06 14:24:30 +00:00
reader_push ( mode_name ) ;
2005-09-20 13:26:39 +00:00
reader_set_prompt ( prompt ) ;
2007-01-29 16:26:24 +00:00
if ( shell )
{
2012-02-06 00:42:24 +00:00
reader_set_complete_function ( & complete ) ;
2007-01-29 16:26:24 +00:00
reader_set_highlight_function ( & highlight_shell ) ;
reader_set_test_function ( & reader_shell_test ) ;
}
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
reader_set_buffer ( commandline , wcslen ( commandline ) ) ;
2007-02-01 00:20:53 +00:00
proc_push_interactive ( 1 ) ;
2011-12-27 03:18:46 +00:00
2009-02-22 16:22:06 +00:00
event_fire_generic ( L " fish_prompt " ) ;
2007-01-15 17:53:46 +00:00
line = reader_readline ( ) ;
2007-02-01 00:20:53 +00:00
proc_pop_interactive ( ) ;
2007-01-15 17:53:46 +00:00
if ( line )
{
buff = wcsdup ( line ) ;
}
else
{
exit_res = STATUS_BUILTIN_ERROR ;
}
2005-09-20 13:26:39 +00:00
reader_pop ( ) ;
}
else
2006-01-30 19:53:10 +00:00
{
2006-03-10 19:51:00 +00:00
int eof = 0 ;
2011-12-27 03:18:46 +00:00
2012-02-22 19:07:34 +00:00
wcstring sb ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
while ( 1 )
{
int finished = 0 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
wchar_t res = 0 ;
static mbstate_t state ;
memset ( & state , ' \0 ' , sizeof ( state ) ) ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
while ( ! finished )
{
char b ;
2006-01-30 19:53:10 +00:00
int read_res = read_blocked ( builtin_stdin , & b , 1 ) ;
2005-09-20 13:26:39 +00:00
if ( read_res < = 0 )
{
eof = 1 ;
break ;
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
int sz = mbrtowc ( & res , & b , 1 , & state ) ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
switch ( sz )
{
case - 1 :
memset ( & state , ' \0 ' , sizeof ( state ) ) ;
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
case - 2 :
break ;
case 0 :
eof = 1 ;
finished = 1 ;
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
default :
finished = 1 ;
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( eof )
break ;
2006-03-10 19:51:00 +00:00
2005-09-20 13:26:39 +00:00
if ( res = = L ' \n ' )
break ;
2012-02-22 19:07:34 +00:00
sb . push_back ( res ) ;
2005-09-20 13:26:39 +00:00
}
2006-03-10 19:51:00 +00:00
2012-02-22 19:07:34 +00:00
if ( sb . size ( ) < 2 & & eof )
2006-03-10 19:51:00 +00:00
{
exit_res = 1 ;
}
2011-12-27 03:18:46 +00:00
2012-02-22 19:07:34 +00:00
buff = wcsdup ( sb . c_str ( ) ) ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2007-01-15 17:53:46 +00:00
if ( i ! = argc & & ! exit_res )
2005-09-20 13:26:39 +00:00
{
2011-12-27 03:18:46 +00:00
2006-04-19 10:08:30 +00:00
wchar_t * state ;
2005-09-20 13:26:39 +00:00
2012-01-14 10:42:17 +00:00
env_var_t ifs = env_get_string ( L " IFS " ) ;
if ( ifs . missing ( ) )
2006-04-19 10:08:30 +00:00
ifs = L " " ;
2011-12-27 03:18:46 +00:00
2012-01-09 18:30:54 +00:00
nxt = wcstok ( buff , ( i < argc - 1 ) ? ifs . c_str ( ) : L " " , & state ) ;
2011-12-27 03:18:46 +00:00
2006-04-19 10:08:30 +00:00
while ( i < argc )
{
env_set ( argv [ i ] , nxt ! = 0 ? nxt : L " " , place ) ;
2011-12-27 03:18:46 +00:00
2006-04-19 10:08:30 +00:00
i + + ;
if ( nxt ! = 0 )
2012-01-09 18:30:54 +00:00
nxt = wcstok ( 0 , ( i < argc - 1 ) ? ifs . c_str ( ) : L " " , & state ) ;
2006-04-19 10:08:30 +00:00
}
2005-09-20 13:26:39 +00:00
}
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
free ( buff ) ;
2006-04-19 10:08:30 +00:00
2006-03-10 19:51:00 +00:00
return exit_res ;
2005-09-20 13:26:39 +00:00
}
2005-10-24 15:26:25 +00:00
/**
The status builtin . Gives various status information on fish .
*/
2012-01-16 20:10:08 +00:00
static int builtin_status ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2011-12-27 03:18:46 +00:00
2006-01-30 19:53:10 +00:00
enum
2005-09-20 13:26:39 +00:00
{
NORMAL ,
2006-01-30 19:53:10 +00:00
IS_SUBST ,
IS_BLOCK ,
IS_INTERACTIVE ,
IS_LOGIN ,
IS_FULL_JOB_CONTROL ,
IS_INTERACTIVE_JOB_CONTROL ,
IS_NO_JOB_CONTROL ,
2006-01-30 17:54:26 +00:00
STACK_TRACE ,
2006-01-30 19:53:10 +00:00
DONE ,
2006-02-14 19:57:47 +00:00
CURRENT_FILENAME ,
CURRENT_LINE_NUMBER
2005-09-20 13:26:39 +00:00
}
;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
int mode = NORMAL ;
2006-01-30 19:53:10 +00:00
int argc = builtin_count_args ( argv ) ;
2006-12-13 14:34:31 +00:00
int res = STATUS_BUILTIN_OK ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
woptind = 0 ;
2006-01-30 19:53:10 +00:00
2007-08-01 22:53:18 +00:00
2006-01-30 19:53:10 +00:00
const struct woption
2005-09-20 13:26:39 +00:00
long_options [ ] =
{
{
2006-01-30 19:53:10 +00:00
L " help " , no_argument , 0 , ' h '
2005-09-20 13:26:39 +00:00
}
,
{
2007-08-01 19:44:50 +00:00
L " is-command-substitution " , no_argument , 0 , ' c '
2005-09-20 13:26:39 +00:00
}
,
{
2007-08-01 19:44:50 +00:00
L " is-block " , no_argument , 0 , ' b '
2005-09-20 13:26:39 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
2007-08-01 19:44:50 +00:00
L " is-interactive " , no_argument , 0 , ' i '
2005-09-20 13:26:39 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
2007-08-01 19:44:50 +00:00
L " is-login " , no_argument , 0 , ' l '
2005-09-20 13:26:39 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
L " is-full-job-control " , no_argument , & mode , IS_FULL_JOB_CONTROL
2006-01-30 17:54:26 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
L " is-interactive-job-control " , no_argument , & mode , IS_INTERACTIVE_JOB_CONTROL
2006-01-30 17:54:26 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
L " is-no-job-control " , no_argument , & mode , IS_NO_JOB_CONTROL
2006-01-30 17:54:26 +00:00
}
,
2006-02-14 19:57:47 +00:00
{
2007-08-01 19:44:50 +00:00
L " current-filename " , no_argument , 0 , ' f '
2006-02-14 19:57:47 +00:00
}
,
{
2007-08-01 19:44:50 +00:00
L " current-line-number " , no_argument , 0 , ' n '
2006-02-14 19:57:47 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
L " job-control " , required_argument , 0 , ' j '
2006-01-30 17:54:26 +00:00
}
,
2006-01-30 19:53:10 +00:00
{
L " print-stack-trace " , no_argument , 0 , ' t '
}
,
{
0 , 0 , 0 , 0
2005-09-20 13:26:39 +00:00
}
}
2006-01-30 19:53:10 +00:00
;
2005-09-20 13:26:39 +00:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
int opt = wgetopt_long ( argc ,
2006-01-30 19:53:10 +00:00
argv ,
2007-08-01 19:44:50 +00:00
L " :cbilfnhj:t " ,
2006-01-30 19:53:10 +00:00
long_options ,
2005-09-20 13:26:39 +00:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
2007-08-01 19:44:50 +00:00
case ' c ' :
mode = IS_SUBST ;
break ;
case ' b ' :
mode = IS_BLOCK ;
break ;
case ' i ' :
mode = IS_INTERACTIVE ;
break ;
case ' l ' :
mode = IS_LOGIN ;
break ;
case ' f ' :
mode = CURRENT_FILENAME ;
break ;
case ' n ' :
mode = CURRENT_LINE_NUMBER ;
break ;
2006-01-30 19:53:10 +00:00
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
2006-01-30 19:53:10 +00:00
case ' j ' :
if ( wcscmp ( woptarg , L " full " ) = = 0 )
job_control_mode = JOB_CONTROL_ALL ;
else if ( wcscmp ( woptarg , L " interactive " ) = = 0 )
job_control_mode = JOB_CONTROL_INTERACTIVE ;
else if ( wcscmp ( woptarg , L " none " ) = = 0 )
job_control_mode = JOB_CONTROL_NONE ;
else
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-30 19:53:10 +00:00
L " %ls: Invalid job control mode '%ls' \n " ,
woptarg ) ;
res = 1 ;
}
2011-12-27 03:18:46 +00:00
mode = DONE ;
2006-01-30 17:54:26 +00:00
break ;
2007-04-24 06:06:20 +00:00
case ' t ' :
mode = STACK_TRACE ;
break ;
2011-12-27 03:18:46 +00:00
2007-04-24 06:06:20 +00:00
2007-08-01 19:44:50 +00:00
case ' : ' :
2012-01-16 20:10:08 +00:00
builtin_missing_argument ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2007-08-01 19:44:50 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
case ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
}
if ( ! res )
{
2005-09-20 13:26:39 +00:00
2006-02-05 21:20:50 +00:00
switch ( mode )
{
2006-02-14 19:57:47 +00:00
case CURRENT_FILENAME :
{
2012-01-16 20:10:08 +00:00
const wchar_t * fn = parser . current_filename ( ) ;
2011-12-27 03:18:46 +00:00
2006-02-14 19:57:47 +00:00
if ( ! fn )
fn = _ ( L " Standard input " ) ;
2011-12-27 03:18:46 +00:00
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , L " %ls \n " , fn ) ;
2011-12-27 03:18:46 +00:00
2006-02-14 19:57:47 +00:00
break ;
}
2011-12-27 03:18:46 +00:00
2006-02-14 19:57:47 +00:00
case CURRENT_LINE_NUMBER :
{
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , L " %d \n " , parser . get_lineno ( ) ) ;
2011-12-27 03:18:46 +00:00
break ;
2006-02-14 19:57:47 +00:00
}
2011-12-27 03:18:46 +00:00
2006-02-05 21:20:50 +00:00
case IS_INTERACTIVE :
return ! is_interactive_session ;
2006-01-30 19:53:10 +00:00
2006-02-05 21:20:50 +00:00
case IS_SUBST :
return ! is_subshell ;
2011-12-27 03:18:46 +00:00
2006-02-05 21:20:50 +00:00
case IS_BLOCK :
return ! is_block ;
2006-01-30 19:53:10 +00:00
2006-02-05 21:20:50 +00:00
case IS_LOGIN :
return ! is_login ;
2011-12-27 03:18:46 +00:00
2006-02-05 21:20:50 +00:00
case IS_FULL_JOB_CONTROL :
return job_control_mode ! = JOB_CONTROL_ALL ;
2006-01-30 19:53:10 +00:00
2006-02-05 21:20:50 +00:00
case IS_INTERACTIVE_JOB_CONTROL :
return job_control_mode ! = JOB_CONTROL_INTERACTIVE ;
2006-01-30 19:53:10 +00:00
2006-02-05 21:20:50 +00:00
case IS_NO_JOB_CONTROL :
return job_control_mode ! = JOB_CONTROL_NONE ;
2006-01-30 17:54:26 +00:00
2006-02-05 21:20:50 +00:00
case STACK_TRACE :
{
2012-02-22 18:51:06 +00:00
parser . stack_trace ( parser . current_block , stdout_buffer ) ;
2006-02-05 21:20:50 +00:00
break ;
}
2006-01-30 19:53:10 +00:00
2006-02-05 21:20:50 +00:00
case NORMAL :
{
if ( is_login )
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , _ ( L " This is a login shell \n " ) ) ;
2006-02-05 21:20:50 +00:00
else
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , _ ( L " This is not a login shell \n " ) ) ;
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , _ ( L " Job control: %ls \n " ) ,
2006-02-14 19:57:47 +00:00
job_control_mode = = JOB_CONTROL_INTERACTIVE ? _ ( L " Only on interactive jobs " ) :
( job_control_mode = = JOB_CONTROL_NONE ? _ ( L " Never " ) : _ ( L " Always " ) ) ) ;
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
parser . stack_trace ( parser . current_block , stdout_buffer ) ;
2006-02-05 21:20:50 +00:00
break ;
}
2006-01-30 19:53:10 +00:00
}
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
return res ;
2005-09-20 13:26:39 +00:00
}
/**
The exit builtin . Calls reader_exit to exit and returns the value specified .
*/
2012-01-16 20:10:08 +00:00
static int builtin_exit ( parser_t & parser , wchar_t * * argv )
2006-01-30 19:53:10 +00:00
{
2005-09-20 13:26:39 +00:00
int argc = builtin_count_args ( argv ) ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
int ec = 0 ;
switch ( argc )
{
case 1 :
2006-06-08 23:57:19 +00:00
{
2006-06-12 16:51:37 +00:00
ec = proc_get_last_status ( ) ;
2005-09-20 13:26:39 +00:00
break ;
2006-06-08 23:57:19 +00:00
}
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
case 2 :
{
wchar_t * end ;
2006-01-30 19:53:10 +00:00
errno = 0 ;
2005-09-20 13:26:39 +00:00
ec = wcstol ( argv [ 1 ] , & end , 10 ) ;
if ( errno | | * end ! = 0 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-09-28 21:39:22 +00:00
_ ( L " %ls: Argument '%ls' must be an integer \n " ) ,
argv [ 0 ] ,
argv [ 1 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
break ;
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
default :
2006-06-08 23:57:19 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-09-28 21:39:22 +00:00
BUILTIN_ERR_TOO_MANY_ARGUMENTS ,
argv [ 0 ] ) ;
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-06-08 23:57:19 +00:00
}
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
}
2006-05-14 10:16:23 +00:00
reader_exit ( 1 , 0 ) ;
2005-09-20 13:26:39 +00:00
return ec ;
}
/**
The cd builtin . Changes the current directory to the one specified
2007-09-28 21:39:22 +00:00
or to $ HOME if none is specified . The directory can be relative to
any directory in the CDPATH variable .
2005-09-20 13:26:39 +00:00
*/
2012-01-16 20:10:08 +00:00
static int builtin_cd ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2012-01-14 10:42:17 +00:00
env_var_t dir_in ;
2012-05-09 09:33:42 +00:00
wchar_t * dir = NULL ;
2006-12-13 14:34:31 +00:00
int res = STATUS_BUILTIN_OK ;
2006-06-17 13:07:08 +00:00
2011-12-27 03:18:46 +00:00
2012-05-05 21:30:20 +00:00
if ( argv [ 1 ] = = NULL )
2005-09-20 13:26:39 +00:00
{
2012-01-09 18:35:51 +00:00
dir_in = env_get_string ( L " HOME " ) ;
2012-01-14 10:42:17 +00:00
if ( dir_in . missing_or_empty ( ) )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Could not find home directory \n " ) ,
argv [ 0 ] ) ;
2006-01-30 19:53:10 +00:00
}
}
2012-05-09 09:33:42 +00:00
else {
2005-09-20 13:26:39 +00:00
dir_in = argv [ 1 ] ;
2012-05-09 09:33:42 +00:00
}
2006-01-30 19:53:10 +00:00
2012-05-09 09:33:42 +00:00
if ( ! dir_in . missing ( ) ) {
dir = path_allocate_cdpath ( dir_in ) ;
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( ! dir )
{
2007-09-20 17:29:28 +00:00
if ( errno = = ENOTDIR )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-09-20 17:29:28 +00:00
_ ( L " %ls: '%ls' is not a directory \n " ) ,
2005-12-16 15:51:16 +00:00
argv [ 0 ] ,
2012-01-09 18:35:51 +00:00
dir_in . c_str ( ) ) ;
2007-09-20 17:29:28 +00:00
}
else if ( errno = = ENOENT )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-09-20 17:29:28 +00:00
_ ( L " %ls: The directory '%ls' does not exist \n " ) ,
argv [ 0 ] ,
2012-01-09 18:35:51 +00:00
dir_in . c_str ( ) ) ;
2007-09-20 17:52:43 +00:00
}
else if ( errno = = EROTTEN )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-09-20 17:52:43 +00:00
_ ( L " %ls: '%ls' is a rotten symlink \n " ) ,
argv [ 0 ] ,
2012-01-09 18:35:51 +00:00
dir_in . c_str ( ) ) ;
2011-12-27 03:18:46 +00:00
}
else
2007-09-20 17:52:43 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-09-20 17:29:28 +00:00
_ ( L " %ls: Unknown error trying to locate directory '%ls' \n " ) ,
argv [ 0 ] ,
2012-01-09 18:35:51 +00:00
dir_in . c_str ( ) ) ;
2011-12-27 03:18:46 +00:00
2007-09-20 17:29:28 +00:00
}
2011-12-27 03:18:46 +00:00
2012-02-26 02:54:49 +00:00
if ( ! get_is_interactive ( ) )
2006-06-08 23:57:19 +00:00
{
2012-02-22 18:51:06 +00:00
stderr_buffer . append ( parser . current_line ( ) ) ;
2006-06-08 23:57:19 +00:00
}
2011-12-27 03:18:46 +00:00
2006-06-12 14:12:33 +00:00
res = 1 ;
2006-01-30 19:53:10 +00:00
}
2006-06-12 14:12:33 +00:00
else if ( wchdir ( dir ) ! = 0 )
2005-09-20 13:26:39 +00:00
{
2007-09-20 17:29:28 +00:00
struct stat buffer ;
int status ;
2011-12-27 03:18:46 +00:00
2007-09-20 17:29:28 +00:00
status = wstat ( dir , & buffer ) ;
if ( ! status & & S_ISDIR ( buffer . st_mode ) )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-09-20 17:29:28 +00:00
_ ( L " %ls: Permission denied: '%ls' \n " ) ,
argv [ 0 ] ,
dir ) ;
2011-12-27 03:18:46 +00:00
2007-09-20 17:29:28 +00:00
}
else
{
2011-12-27 03:18:46 +00:00
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: '%ls' is not a directory \n " ) ,
2005-12-16 15:51:16 +00:00
argv [ 0 ] ,
dir ) ;
2007-09-20 17:29:28 +00:00
}
2011-12-27 03:18:46 +00:00
2012-02-26 02:54:49 +00:00
if ( ! get_is_interactive ( ) )
2006-06-08 23:57:19 +00:00
{
2012-02-22 18:51:06 +00:00
stderr_buffer . append ( parser . current_line ( ) ) ;
2006-06-08 23:57:19 +00:00
}
2011-12-27 03:18:46 +00:00
2006-06-12 14:12:33 +00:00
res = 1 ;
2005-09-20 13:26:39 +00:00
}
2008-01-16 22:26:28 +00:00
else if ( ! env_set_pwd ( ) )
2005-09-20 13:26:39 +00:00
{
res = 1 ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , _ ( L " %ls: Could not set PWD variable \n " ) , argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2012-02-01 00:50:03 +00:00
free ( dir ) ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
return res ;
}
2008-01-13 16:47:47 +00:00
/**
Implementation of the builtin count command , used to count the
number of arguments sent to it .
*/
2012-01-19 18:28:44 +00:00
static int builtin_count ( parser_t & parser , wchar_t * * argv )
2007-07-31 21:23:32 +00:00
{
int argc ;
argc = builtin_count_args ( argv ) ;
2012-02-22 18:51:06 +00:00
append_format ( stdout_buffer , L " %d \n " , argc - 1 ) ;
2007-09-09 13:57:34 +00:00
return ! ( argc - 1 ) ;
2007-07-31 21:23:32 +00:00
}
2005-09-20 13:26:39 +00:00
2008-01-13 16:47:47 +00:00
/**
Implementation of the builtin contains command , used to check if a
specified string is part of a list .
*/
2012-01-16 20:10:08 +00:00
static int builtin_contains ( parser_t & parser , wchar_t * * argv )
2007-08-01 22:53:18 +00:00
{
int argc ;
argc = builtin_count_args ( argv ) ;
int i ;
wchar_t * needle ;
2011-12-27 03:18:46 +00:00
2007-08-01 22:53:18 +00:00
woptind = 0 ;
const struct woption
long_options [ ] =
{
{
L " help " , no_argument , 0 , ' h '
}
,
{
0 , 0 , 0 , 0
}
}
;
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
2007-08-14 21:42:57 +00:00
L " +h " ,
2007-08-01 22:53:18 +00:00
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
2012-03-26 08:21:10 +00:00
assert ( opt_index > = 0 & & opt_index < sizeof long_options / sizeof * long_options ) ;
2007-08-01 22:53:18 +00:00
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-08-01 22:53:18 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2007-08-01 22:53:18 +00:00
return STATUS_BUILTIN_ERROR ;
case ' h ' :
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2007-08-01 22:53:18 +00:00
return STATUS_BUILTIN_OK ;
case ' : ' :
2012-01-16 20:10:08 +00:00
builtin_missing_argument ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2007-08-01 22:53:18 +00:00
return STATUS_BUILTIN_ERROR ;
case ' ? ' :
2012-01-16 20:10:08 +00:00
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
2007-08-01 22:53:18 +00:00
return STATUS_BUILTIN_ERROR ;
}
2011-12-27 03:18:46 +00:00
2007-08-01 22:53:18 +00:00
}
needle = argv [ woptind ] ;
if ( ! needle )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , _ ( L " %ls: Key not specified \n " ) , argv [ 0 ] ) ;
2007-08-01 22:53:18 +00:00
}
2011-12-27 03:18:46 +00:00
2007-08-01 22:53:18 +00:00
for ( i = woptind + 1 ; i < argc ; i + + )
{
2011-12-27 03:18:46 +00:00
2007-08-01 22:53:18 +00:00
if ( ! wcscmp ( needle , argv [ i ] ) )
{
return 0 ;
}
}
return 1 ;
2007-08-14 21:42:57 +00:00
2007-08-01 22:53:18 +00:00
}
2005-09-20 13:26:39 +00:00
/**
2006-01-30 19:53:10 +00:00
The . ( dot ) builtin , sometimes called source . Evaluates the contents of a file .
2005-09-20 13:26:39 +00:00
*/
2012-01-16 20:10:08 +00:00
static int builtin_source ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2012-03-02 08:27:40 +00:00
ASSERT_IS_MAIN_THREAD ( ) ;
2005-10-19 12:07:44 +00:00
int fd ;
2006-12-13 14:34:31 +00:00
int res = STATUS_BUILTIN_OK ;
2005-12-15 17:21:22 +00:00
struct stat buf ;
2005-12-16 15:51:16 +00:00
int argc ;
2006-01-30 19:53:10 +00:00
argc = builtin_count_args ( argv ) ;
2011-12-27 03:18:46 +00:00
const wchar_t * fn ;
2007-04-22 21:19:47 +00:00
const wchar_t * fn_intern ;
2011-12-27 03:18:46 +00:00
2006-01-30 19:53:10 +00:00
2007-04-22 21:19:47 +00:00
if ( argc < 2 | | ( wcscmp ( argv [ 1 ] , L " - " ) = = 0 ) )
2006-01-30 19:53:10 +00:00
{
2007-04-22 21:19:47 +00:00
fn = L " - " ;
fn_intern = fn ;
fd = dup ( builtin_stdin ) ;
2005-09-20 13:26:39 +00:00
}
else
{
2011-12-27 03:18:46 +00:00
2012-03-02 19:12:08 +00:00
if ( ( fd = wopen_cloexec ( argv [ 1 ] , O_RDONLY ) ) = = - 1 )
2007-04-22 21:19:47 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer , _ ( L " %ls: Error encountered while sourcing file '%ls': \n " ) , argv [ 0 ] , argv [ 1 ] ) ;
2007-09-24 08:14:28 +00:00
builtin_wperror ( L " . " ) ;
2007-04-22 21:19:47 +00:00
return STATUS_BUILTIN_ERROR ;
}
2012-03-02 19:12:08 +00:00
if ( fstat ( fd , & buf ) = = - 1 )
2007-04-22 21:19:47 +00:00
{
2012-03-02 19:12:08 +00:00
close ( fd ) ;
append_format ( stderr_buffer , _ ( L " %ls: Error encountered while sourcing file '%ls': \n " ) , argv [ 0 ] , argv [ 1 ] ) ;
builtin_wperror ( L " . " ) ;
2007-04-22 21:19:47 +00:00
return STATUS_BUILTIN_ERROR ;
}
2012-03-02 19:12:08 +00:00
if ( ! S_ISREG ( buf . st_mode ) )
2007-04-22 21:19:47 +00:00
{
2012-03-02 19:12:08 +00:00
close ( fd ) ;
append_format ( stderr_buffer , _ ( L " %ls: '%ls' is not a file \n " ) , argv [ 0 ] , argv [ 1 ] ) ;
2007-04-22 21:19:47 +00:00
return STATUS_BUILTIN_ERROR ;
}
fn = wrealpath ( argv [ 1 ] , 0 ) ;
2006-02-02 15:23:56 +00:00
if ( ! fn )
{
fn_intern = intern ( argv [ 1 ] ) ;
}
else
{
fn_intern = intern ( fn ) ;
2011-12-27 03:18:46 +00:00
free ( ( void * ) fn ) ;
2006-02-02 15:23:56 +00:00
}
2007-04-22 21:19:47 +00:00
}
2011-12-27 03:18:46 +00:00
2012-01-16 20:10:08 +00:00
parser . push_block ( SOURCE ) ;
2007-04-22 21:19:47 +00:00
reader_push_current_filename ( fn_intern ) ;
2011-12-27 03:18:46 +00:00
2012-02-13 19:55:02 +00:00
// PCA We need the state to be a wcstring; it would be nice to figure out how to restore this optimization however
//parser.current_block->state1<const wchar_t *>() = fn_intern;
parser . current_block - > state1 < wcstring > ( ) = fn_intern ;
2011-12-27 03:18:46 +00:00
2012-01-14 07:44:18 +00:00
parse_util_set_argv ( ( argc > 2 ) ? ( argv + 2 ) : ( argv + 1 ) , wcstring_list_t ( ) ) ;
2011-12-27 03:18:46 +00:00
2007-04-25 18:30:02 +00:00
res = reader_read ( fd , real_io ) ;
2011-12-27 03:18:46 +00:00
2012-01-16 20:10:08 +00:00
parser . pop_block ( ) ;
2011-12-27 03:18:46 +00:00
2007-04-22 21:19:47 +00:00
if ( res )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-09-08 22:27:25 +00:00
_ ( L " %ls: Error while reading file '%ls' \n " ) ,
argv [ 0 ] ,
2009-02-22 20:28:52 +00:00
fn_intern = = intern_static ( L " - " ) ? L " <stdin> " : fn_intern ) ;
2005-09-20 13:26:39 +00:00
}
2007-10-05 14:58:08 +00:00
else
{
res = proc_get_last_status ( ) ;
}
2011-12-27 03:18:46 +00:00
2007-04-22 21:19:47 +00:00
/*
Do not close fd after calling reader_read . reader_read
automatically closes it before calling eval .
*/
2011-12-27 03:18:46 +00:00
2007-04-22 21:19:47 +00:00
reader_pop_current_filename ( ) ;
2005-09-20 13:26:39 +00:00
return res ;
}
/**
Make the specified job the first job of the job list . Moving jobs
around in the list makes the list reflect the order in which the
2005-10-08 09:33:10 +00:00
jobs were used .
2005-09-20 13:26:39 +00:00
*/
static void make_first ( job_t * j )
{
2012-01-30 00:36:21 +00:00
job_promote ( j ) ;
2005-09-20 13:26:39 +00:00
}
/**
Builtin for putting a job in the foreground
*/
2012-01-16 20:10:08 +00:00
static int builtin_fg ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2012-01-30 00:36:21 +00:00
job_t * j = NULL ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( argv [ 1 ] = = 0 )
{
/*
2006-06-03 22:35:33 +00:00
Select last constructed job ( I . e . first job in the job que )
that is possible to put in the foreground
2005-09-20 13:26:39 +00:00
*/
2012-01-30 00:36:21 +00:00
job_iterator_t jobs ;
while ( ( j = jobs . next ( ) ) )
2006-01-19 13:15:15 +00:00
{
2011-12-27 03:18:46 +00:00
if ( job_get_flag ( j , JOB_CONSTRUCTED ) & & ( ! job_is_completed ( j ) ) & &
2006-10-25 20:47:59 +00:00
( ( job_is_stopped ( j ) | | ( ! job_get_flag ( j , JOB_FOREGROUND ) ) ) & & job_get_flag ( j , JOB_CONTROL ) ) )
2006-06-08 23:57:19 +00:00
{
2006-01-19 13:15:15 +00:00
break ;
2006-06-08 23:57:19 +00:00
}
2006-01-30 19:53:10 +00:00
}
2006-01-18 16:47:50 +00:00
if ( ! j )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-19 13:15:15 +00:00
_ ( L " %ls: There are no suitable jobs \n " ) ,
2006-01-18 16:47:50 +00:00
argv [ 0 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-18 16:47:50 +00:00
}
2005-09-20 13:26:39 +00:00
}
else if ( argv [ 2 ] ! = 0 )
{
/*
Specifying what more than one job to put to the foreground
is a syntax error , we still try to locate the job argv [ 1 ] ,
since we want to know if this is an ambigous job
specification or if this is an malformed job id
*/
2006-10-04 21:42:04 +00:00
wchar_t * endptr ;
int pid ;
int found_job = 0 ;
2011-12-27 03:18:46 +00:00
2006-10-04 21:42:04 +00:00
errno = 0 ;
pid = wcstol ( argv [ 1 ] , & endptr , 10 ) ;
if ( ! ( * endptr | | errno ) )
2011-12-27 03:18:46 +00:00
{
2006-10-04 21:42:04 +00:00
j = job_get_from_pid ( pid ) ;
if ( j )
found_job = 1 ;
}
2011-12-27 03:18:46 +00:00
2006-10-04 21:42:04 +00:00
if ( found_job )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-02-05 21:20:50 +00:00
_ ( L " %ls: Ambiguous job \n " ) ,
2006-01-30 19:53:10 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
}
else
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-30 19:53:10 +00:00
_ ( L " %ls: '%ls' is not a job \n " ) ,
argv [ 0 ] ,
2006-01-04 12:51:02 +00:00
argv [ 1 ] ) ;
2005-09-20 13:26:39 +00:00
}
2006-10-04 21:42:04 +00:00
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-30 19:53:10 +00:00
2006-01-19 13:15:15 +00:00
j = 0 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
else
{
2011-12-27 03:18:46 +00:00
wchar_t * end ;
2006-10-04 21:42:04 +00:00
int pid ;
errno = 0 ;
pid = abs ( wcstol ( argv [ 1 ] , & end , 10 ) ) ;
2011-12-27 03:18:46 +00:00
2006-10-04 21:42:04 +00:00
if ( * end | | errno )
2006-01-19 13:15:15 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-10-04 21:39:48 +00:00
BUILTIN_ERR_NOT_NUMBER ,
2006-04-24 15:34:34 +00:00
argv [ 0 ] ,
argv [ 1 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-01-19 13:15:15 +00:00
}
2006-04-24 15:34:34 +00:00
else
2006-01-30 17:54:26 +00:00
{
2006-04-24 15:34:34 +00:00
j = job_get_from_pid ( pid ) ;
2006-10-25 20:47:59 +00:00
if ( ! j | | ! job_get_flag ( j , JOB_CONSTRUCTED ) | | job_is_completed ( j ) )
2006-04-24 15:34:34 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-04-24 15:34:34 +00:00
_ ( L " %ls: No suitable job: %d \n " ) ,
argv [ 0 ] ,
pid ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-04-24 15:34:34 +00:00
j = 0 ;
}
2006-10-25 20:47:59 +00:00
else if ( ! job_get_flag ( j , JOB_CONTROL ) )
2006-04-24 15:34:34 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-04-24 15:34:34 +00:00
_ ( L " %ls: Can't put job %d, '%ls' to foreground because it is not under job control \n " ) ,
argv [ 0 ] ,
pid ,
2012-03-09 07:21:07 +00:00
j - > command_wcstr ( ) ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-04-24 15:34:34 +00:00
j = 0 ;
}
2006-01-30 17:54:26 +00:00
}
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2006-01-19 13:15:15 +00:00
if ( j )
2005-09-20 13:26:39 +00:00
{
if ( builtin_err_redirect )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2005-12-15 13:59:02 +00:00
FG_MSG ,
2006-01-30 19:53:10 +00:00
j - > job_id ,
2012-03-09 07:21:07 +00:00
j - > command_wcstr ( ) ) ;
2005-09-20 13:26:39 +00:00
}
else
{
2005-12-15 13:59:02 +00:00
/*
If we aren ' t redirecting , send output to real stderr ,
since stuff in sb_err won ' t get printed until the
command finishes .
*/
2005-09-20 13:26:39 +00:00
fwprintf ( stderr ,
2005-12-15 13:59:02 +00:00
FG_MSG ,
2006-01-30 19:53:10 +00:00
j - > job_id ,
2012-03-09 07:21:07 +00:00
j - > command_wcstr ( ) ) ;
2005-09-20 13:26:39 +00:00
}
2005-12-15 13:59:02 +00:00
2012-03-09 07:21:07 +00:00
wchar_t * ft = tok_first ( j - > command_wcstr ( ) ) ;
2006-01-19 13:15:15 +00:00
if ( ft ! = 0 )
env_set ( L " _ " , ft , ENV_EXPORT ) ;
free ( ft ) ;
reader_write_title ( ) ;
2006-01-30 19:53:10 +00:00
2006-01-19 13:15:15 +00:00
make_first ( j ) ;
2006-10-25 20:47:59 +00:00
job_set_flag ( j , JOB_FOREGROUND , 1 ) ;
2006-01-30 19:53:10 +00:00
2006-01-19 13:15:15 +00:00
job_continue ( j , job_is_stopped ( j ) ) ;
}
return j ! = 0 ;
2005-09-20 13:26:39 +00:00
}
/**
Helper function for builtin_bg ( )
*/
2012-01-16 20:10:08 +00:00
static int send_to_bg ( parser_t & parser , job_t * j , const wchar_t * name )
2005-09-20 13:26:39 +00:00
{
if ( j = = 0 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Unknown job '%ls' \n " ) ,
L " bg " ,
name ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , L " bg " , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 19:53:10 +00:00
}
2006-10-25 20:47:59 +00:00
else if ( ! job_get_flag ( j , JOB_CONTROL ) )
2006-01-30 17:54:26 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-30 17:54:26 +00:00
_ ( L " %ls: Can't put job %d, '%ls' to background because it is not under job control \n " ) ,
L " bg " ,
j - > job_id ,
2012-03-09 07:21:07 +00:00
j - > command_wcstr ( ) ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , L " bg " , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2006-01-30 17:54:26 +00:00
}
2005-09-20 13:26:39 +00:00
else
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " Send job %d '%ls' to background \n " ) ,
2005-09-20 13:26:39 +00:00
j - > job_id ,
2012-03-09 07:21:07 +00:00
j - > command_wcstr ( ) ) ;
2005-09-20 13:26:39 +00:00
}
make_first ( j ) ;
2006-10-25 20:47:59 +00:00
job_set_flag ( j , JOB_FOREGROUND , 0 ) ;
2005-09-20 13:26:39 +00:00
job_continue ( j , job_is_stopped ( j ) ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
/**
Builtin for putting a job in the background
*/
2012-01-16 20:10:08 +00:00
static int builtin_bg ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2006-12-13 14:34:31 +00:00
int res = STATUS_BUILTIN_OK ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( argv [ 1 ] = = 0 )
{
job_t * j ;
2012-01-30 00:36:21 +00:00
job_iterator_t jobs ;
while ( ( j = jobs . next ( ) ) )
{
2006-10-25 20:47:59 +00:00
if ( job_is_stopped ( j ) & & job_get_flag ( j , JOB_CONTROL ) & & ( ! job_is_completed ( j ) ) )
2006-06-08 23:57:19 +00:00
{
2006-01-19 13:15:15 +00:00
break ;
2006-06-08 23:57:19 +00:00
}
2006-01-19 13:15:15 +00:00
}
2011-12-27 03:18:46 +00:00
2006-01-19 13:15:15 +00:00
if ( ! j )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-19 13:15:15 +00:00
_ ( L " %ls: There are no suitable jobs \n " ) ,
argv [ 0 ] ) ;
res = 1 ;
}
else
{
2012-01-16 20:10:08 +00:00
res = send_to_bg ( parser , j , _ ( L " (default) " ) ) ;
2006-01-19 13:15:15 +00:00
}
2005-09-20 13:26:39 +00:00
}
2006-01-19 13:15:15 +00:00
else
2005-09-20 13:26:39 +00:00
{
2007-01-09 00:21:44 +00:00
wchar_t * end ;
int i ;
int pid ;
int err = 0 ;
2011-12-27 03:18:46 +00:00
2007-01-09 00:21:44 +00:00
for ( i = 1 ; argv [ i ] ; i + + )
{
errno = 0 ;
pid = ( int ) wcstol ( argv [ i ] , & end , 10 ) ;
if ( errno | | pid < 0 | | * end | | ! job_get_from_pid ( pid ) )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2007-01-09 00:21:44 +00:00
_ ( L " %ls: '%ls' is not a job \n " ) ,
argv [ 0 ] ,
argv [ i ] ) ;
err = 1 ;
break ;
2011-12-27 03:18:46 +00:00
}
2007-01-09 00:21:44 +00:00
}
if ( ! err )
2006-01-19 13:15:15 +00:00
{
2007-01-09 00:21:44 +00:00
for ( i = 1 ; ! res & & argv [ i ] ; i + + )
{
pid = ( int ) wcstol ( argv [ i ] , 0 , 10 ) ;
2012-01-16 20:10:08 +00:00
res | = send_to_bg ( parser , job_get_from_pid ( pid ) , * argv ) ;
2007-01-09 00:21:44 +00:00
}
2006-01-19 13:15:15 +00:00
}
2005-09-20 13:26:39 +00:00
}
2011-12-27 03:18:46 +00:00
2006-01-19 13:15:15 +00:00
return res ;
2005-09-20 13:26:39 +00:00
}
/**
Builtin for looping over a list
*/
2012-01-16 20:10:08 +00:00
static int builtin_for ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
int argc = builtin_count_args ( argv ) ;
2006-12-13 14:34:31 +00:00
int res = STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
2006-01-30 19:53:10 +00:00
if ( argc < 3 )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-09-26 12:41:09 +00:00
BUILTIN_FOR_ERR_COUNT ,
2006-09-19 14:21:40 +00:00
argv [ 0 ] ,
argc ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2005-09-20 13:26:39 +00:00
}
2006-04-21 14:29:39 +00:00
else if ( wcsvarname ( argv [ 1 ] ) )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-10-01 15:57:34 +00:00
BUILTIN_FOR_ERR_NAME ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ 1 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2005-09-20 13:26:39 +00:00
}
else if ( wcscmp ( argv [ 2 ] , L " in " ) ! = 0 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-05-21 22:16:04 +00:00
BUILTIN_FOR_ERR_IN ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2005-09-20 13:26:39 +00:00
}
else
{
res = 0 ;
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( res )
{
2012-01-16 20:10:08 +00:00
parser . push_block ( FAKE ) ;
2005-09-20 13:26:39 +00:00
}
else
{
2012-01-16 20:10:08 +00:00
parser . push_block ( FOR ) ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
int i ;
2012-02-08 01:06:45 +00:00
const wcstring for_variable = argv [ 1 ] ;
2012-01-16 20:10:08 +00:00
parser . current_block - > tok_pos = parser . get_pos ( ) ;
2012-02-08 01:06:45 +00:00
parser . current_block - > state1 < wcstring > ( ) = for_variable ;
2006-01-30 19:53:10 +00:00
2012-02-08 01:06:45 +00:00
wcstring_list_t & for_vars = parser . current_block - > state2 < wcstring_list_t > ( ) ;
2005-09-20 13:26:39 +00:00
for ( i = argc - 1 ; i > 3 ; i - - )
2012-02-08 01:06:45 +00:00
for_vars . push_back ( argv [ i ] ) ;
2006-02-06 18:11:01 +00:00
2005-09-20 13:26:39 +00:00
if ( argc > 3 )
{
2012-02-08 01:06:45 +00:00
env_set ( for_variable . c_str ( ) , argv [ 3 ] , ENV_LOCAL ) ;
2005-09-20 13:26:39 +00:00
}
else
{
2012-01-16 20:10:08 +00:00
parser . current_block - > skip = 1 ;
2006-01-30 19:53:10 +00:00
}
2005-09-20 13:26:39 +00:00
}
return res ;
}
2005-10-24 15:26:25 +00:00
/**
The begin builtin . Creates a nex block .
*/
2012-01-16 20:10:08 +00:00
static int builtin_begin ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2012-01-16 20:10:08 +00:00
parser . push_block ( BEGIN ) ;
parser . current_block - > tok_pos = parser . get_pos ( ) ;
2006-07-12 17:31:41 +00:00
return proc_get_last_status ( ) ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
/**
Builtin for ending a block of code , such as a for - loop or an if statement .
2006-01-30 19:53:10 +00:00
The end command is whare a lot of the block - level magic happens .
2005-09-20 13:26:39 +00:00
*/
2012-01-16 20:10:08 +00:00
static int builtin_end ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2012-01-16 20:10:08 +00:00
if ( ! parser . current_block - > outer )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Not inside of block \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
else
{
/**
By default , ' end ' kills the current block scope . But if we
are rewinding a loop , this should be set to false , so that
variables in the current loop scope won ' t die between laps .
*/
int kill_block = 1 ;
2006-01-30 19:53:10 +00:00
2012-01-16 20:10:08 +00:00
switch ( parser . current_block - > type )
2005-09-20 13:26:39 +00:00
{
case WHILE :
{
/*
If this is a while loop , we rewind the loop unless
it ' s the last lap , in which case we continue .
*/
2012-01-16 20:10:08 +00:00
if ( ! ( parser . current_block - > skip & & ( parser . current_block - > loop_status ! = LOOP_CONTINUE ) ) )
2005-09-20 13:26:39 +00:00
{
2012-01-16 20:10:08 +00:00
parser . current_block - > loop_status = LOOP_NORMAL ;
parser . current_block - > skip = 0 ;
2005-09-20 13:26:39 +00:00
kill_block = 0 ;
2012-01-16 20:10:08 +00:00
parser . set_pos ( parser . current_block - > tok_pos ) ;
2012-02-08 01:06:45 +00:00
parser . current_block - > state1 < int > ( ) = WHILE_TEST_AGAIN ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
break ;
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
case IF :
case SUBST :
case BEGIN :
/*
2006-06-03 22:35:33 +00:00
Nothing special happens at the end of these commands . The scope just ends .
2005-09-20 13:26:39 +00:00
*/
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
break ;
case FOR :
{
/*
set loop variable to next element , and rewind to the beginning of the block .
*/
2012-02-08 01:06:45 +00:00
wcstring_list_t & for_vars = parser . current_block - > state2 < wcstring_list_t > ( ) ;
2012-01-16 20:10:08 +00:00
if ( parser . current_block - > loop_status = = LOOP_BREAK )
2005-09-20 13:26:39 +00:00
{
2012-02-08 01:06:45 +00:00
for_vars . clear ( ) ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2012-02-08 01:06:45 +00:00
if ( ! for_vars . empty ( ) )
2005-09-20 13:26:39 +00:00
{
2012-02-08 01:06:45 +00:00
const wcstring val = for_vars . back ( ) ;
for_vars . pop_back ( ) ;
const wcstring for_variable = parser . current_block - > state1 < wcstring > ( ) ;
env_set ( for_variable . c_str ( ) , val . c_str ( ) , ENV_LOCAL ) ;
2012-01-16 20:10:08 +00:00
parser . current_block - > loop_status = LOOP_NORMAL ;
parser . current_block - > skip = 0 ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
kill_block = 0 ;
2012-01-16 20:10:08 +00:00
parser . set_pos ( parser . current_block - > tok_pos ) ;
2005-09-20 13:26:39 +00:00
}
break ;
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
case FUNCTION_DEF :
{
2011-12-27 03:18:46 +00:00
2012-02-08 06:10:35 +00:00
function_data_t * d = parser . current_block - > function_data . get ( ) ;
2011-12-27 03:18:46 +00:00
2006-09-08 14:12:41 +00:00
if ( d )
{
2007-04-22 22:10:33 +00:00
/**
Copy the text from the beginning of the function
until the end command and use as the new definition
for the specified function
*/
2012-01-16 20:10:08 +00:00
wchar_t * def = wcsndup ( parser . get_buffer ( ) + parser . current_block - > tok_pos ,
parser . get_job_pos ( ) - parser . current_block - > tok_pos ) ;
2007-04-22 22:10:33 +00:00
d - > definition = def ;
2011-12-27 03:18:46 +00:00
2012-03-03 23:20:30 +00:00
function_add ( * d , parser ) ;
2007-04-22 22:10:33 +00:00
free ( def ) ;
2006-09-08 14:12:41 +00:00
}
else
{
2011-12-27 03:18:46 +00:00
debug ( 0 ,
2006-11-17 14:58:25 +00:00
_ ( L " %ls: Missing function definition information. " ) ,
argv [ 0 ] ) ;
bugreport ( ) ;
2006-09-08 14:12:41 +00:00
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
break ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
if ( kill_block )
{
2012-01-16 20:10:08 +00:00
parser . pop_block ( ) ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
/*
If everything goes ok , return status of last command to execute .
*/
return proc_get_last_status ( ) ;
2006-01-30 19:53:10 +00:00
}
2005-09-20 13:26:39 +00:00
}
/**
Builtin for executing commands if an if statement is false
*/
2012-01-16 20:10:08 +00:00
static int builtin_else ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2012-01-16 20:10:08 +00:00
if ( parser . current_block = = 0 | |
parser . current_block - > type ! = IF | |
2012-02-08 01:06:45 +00:00
parser . current_block - > state1 < int > ( ) ! = 1 )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Not inside of 'if' block \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
else
{
2012-02-08 01:06:45 +00:00
int & if_state = parser . current_block - > state1 < int > ( ) ;
if_state + + ;
2012-01-16 20:10:08 +00:00
parser . current_block - > skip = ! parser . current_block - > skip ;
2005-09-20 13:26:39 +00:00
env_pop ( ) ;
env_push ( 0 ) ;
}
/*
If everything goes ok , return status of last command to execute .
*/
return proc_get_last_status ( ) ;
}
/**
This function handles both the ' continue ' and the ' break ' builtins
that are used for loop control .
*/
2012-01-16 20:10:08 +00:00
static int builtin_break_continue ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
int is_break = ( wcscmp ( argv [ 0 ] , L " break " ) = = 0 ) ;
int argc = builtin_count_args ( argv ) ;
2006-01-30 19:53:10 +00:00
2012-01-16 20:10:08 +00:00
block_t * b = parser . current_block ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( argc ! = 1 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
2005-12-15 13:59:02 +00:00
argv [ 1 ] ) ;
2006-01-04 12:51:02 +00:00
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
while ( ( b ! = 0 ) & &
( b - > type ! = WHILE ) & &
2005-09-20 13:26:39 +00:00
( b - > type ! = FOR ) )
{
b = b - > outer ;
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( b = = 0 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-30 19:53:10 +00:00
_ ( L " %ls: Not inside of loop \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2012-01-16 20:10:08 +00:00
b = parser . current_block ;
2006-01-30 19:53:10 +00:00
while ( ( b - > type ! = WHILE ) & &
2005-09-20 13:26:39 +00:00
( b - > type ! = FOR ) )
{
b - > skip = 1 ;
b = b - > outer ;
}
b - > skip = 1 ;
b - > loop_status = is_break ? LOOP_BREAK : LOOP_CONTINUE ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
2008-01-13 16:47:47 +00:00
/**
Implementation of the builtin count command , used to launch the
interactive debugger .
*/
2012-01-16 20:10:08 +00:00
static int builtin_breakpoint ( parser_t & parser , wchar_t * * argv )
2006-11-11 10:54:00 +00:00
{
2012-01-16 20:10:08 +00:00
parser . push_block ( BREAKPOINT ) ;
2011-12-27 03:18:46 +00:00
2010-09-18 12:26:54 +00:00
reader_read ( STDIN_FILENO , real_io ) ;
2011-12-27 03:18:46 +00:00
2012-01-16 20:10:08 +00:00
parser . pop_block ( ) ;
2011-12-27 03:18:46 +00:00
2006-11-11 10:54:00 +00:00
return proc_get_last_status ( ) ;
}
2005-09-20 13:26:39 +00:00
/**
Function for handling the \ c return builtin
*/
2012-01-16 20:10:08 +00:00
static int builtin_return ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
int argc = builtin_count_args ( argv ) ;
2006-06-12 16:48:54 +00:00
int status = proc_get_last_status ( ) ;
2006-01-30 19:53:10 +00:00
2012-01-16 20:10:08 +00:00
block_t * b = parser . current_block ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
switch ( argc )
{
case 1 :
break ;
case 2 :
{
wchar_t * end ;
2006-01-30 19:53:10 +00:00
errno = 0 ;
2005-09-20 13:26:39 +00:00
status = wcstol ( argv [ 1 ] , & end , 10 ) ;
if ( errno | | * end ! = 0 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-30 19:53:10 +00:00
_ ( L " %ls: Argument '%ls' must be an integer \n " ) ,
argv [ 0 ] ,
2005-12-15 13:59:02 +00:00
argv [ 1 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
break ;
2005-09-20 13:26:39 +00:00
}
default :
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-30 19:53:10 +00:00
_ ( L " %ls: Too many arguments \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
while ( ( b ! = 0 ) & &
2011-12-27 03:18:46 +00:00
( b - > type ! = FUNCTION_CALL & &
2008-01-09 03:01:36 +00:00
b - > type ! = FUNCTION_CALL_NO_SHADOW ) )
2005-09-20 13:26:39 +00:00
{
b = b - > outer ;
}
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( b = = 0 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-30 19:53:10 +00:00
_ ( L " %ls: Not inside of function \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2006-01-30 19:53:10 +00:00
2012-01-16 20:10:08 +00:00
b = parser . current_block ;
2008-01-09 03:01:36 +00:00
while ( ( b - > type ! = FUNCTION_CALL & &
b - > type ! = FUNCTION_CALL_NO_SHADOW ) )
2005-09-20 13:26:39 +00:00
{
2006-08-31 20:53:20 +00:00
b - > type = FAKE ;
2005-09-20 13:26:39 +00:00
b - > skip = 1 ;
b = b - > outer ;
}
b - > skip = 1 ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
return status ;
}
/**
2006-10-01 15:57:34 +00:00
Builtin for executing one of several blocks of commands depending
on the value of an argument .
2005-09-20 13:26:39 +00:00
*/
2012-01-16 20:10:08 +00:00
static int builtin_switch ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
2006-12-13 14:34:31 +00:00
int res = STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
int argc = builtin_count_args ( argv ) ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
if ( argc ! = 2 )
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Expected exactly one argument, got %d \n " ) ,
2005-09-20 13:26:39 +00:00
argv [ 0 ] ,
argc - 1 ) ;
2006-01-30 19:53:10 +00:00
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2005-09-20 13:26:39 +00:00
res = 1 ;
2012-01-16 20:10:08 +00:00
parser . push_block ( FAKE ) ;
2005-09-20 13:26:39 +00:00
}
else
{
2012-01-16 20:10:08 +00:00
parser . push_block ( SWITCH ) ;
2012-02-08 01:06:45 +00:00
parser . current_block - > state1 < wcstring > ( ) = argv [ 1 ] ;
2012-01-16 20:10:08 +00:00
parser . current_block - > skip = 1 ;
2012-02-08 01:06:45 +00:00
parser . current_block - > state2 < int > ( ) = 0 ;
2005-09-20 13:26:39 +00:00
}
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
return res ;
}
/**
2006-10-01 15:57:34 +00:00
Builtin used together with the switch builtin for conditional
execution
2005-09-20 13:26:39 +00:00
*/
2012-01-16 20:10:08 +00:00
static int builtin_case ( parser_t & parser , wchar_t * * argv )
2005-09-20 13:26:39 +00:00
{
int argc = builtin_count_args ( argv ) ;
int i ;
wchar_t * unescaped = 0 ;
2011-12-27 03:18:46 +00:00
2012-01-16 20:10:08 +00:00
if ( parser . current_block - > type ! = SWITCH )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
append_format ( stderr_buffer ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: 'case' command while not in switch block \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2006-10-09 01:21:02 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2011-12-27 03:18:46 +00:00
2012-01-16 20:10:08 +00:00
parser . current_block - > skip = 1 ;
2011-12-27 03:18:46 +00:00
2012-02-08 01:06:45 +00:00
if ( parser . current_block - > state2 < int > ( ) )
2005-09-20 13:26:39 +00:00
{
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
for ( i = 1 ; i < argc ; i + + )
{
2006-08-28 12:02:44 +00:00
int match ;
2011-12-27 03:18:46 +00:00
2006-08-28 12:02:44 +00:00
unescaped = parse_util_unescape_wildcards ( argv [ i ] ) ;
2012-02-08 01:06:45 +00:00
const wcstring & switch_value = parser . current_block - > state1 < wcstring > ( ) ;
match = wildcard_match ( switch_value , unescaped ) ;
2006-08-28 12:02:44 +00:00
free ( unescaped ) ;
2011-12-27 03:18:46 +00:00
2006-08-28 12:02:44 +00:00
if ( match )
2005-09-20 13:26:39 +00:00
{
2012-01-16 20:10:08 +00:00
parser . current_block - > skip = 0 ;
2012-02-08 01:06:45 +00:00
parser . current_block - > state2 < int > ( ) = 1 ;
2006-01-30 19:53:10 +00:00
break ;
2005-09-20 13:26:39 +00:00
}
}
2011-12-27 03:18:46 +00:00
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
/*
END OF BUILTIN COMMANDS
2012-02-01 03:47:56 +00:00
Below are functions for handling the builtin commands .
THESE MUST BE SORTED BY NAME ! Completion lookup uses binary search .
2005-09-20 13:26:39 +00:00
*/
2005-12-15 13:59:02 +00:00
2006-06-17 13:07:08 +00:00
/**
2012-02-01 03:47:56 +00:00
Data about all the builtin commands in fish .
Functions that are bound to builtin_generic are handled directly by the parser .
2006-06-17 13:07:08 +00:00
*/
2012-02-01 03:47:56 +00:00
static const builtin_data_t builtin_datas [ ] =
2005-09-20 13:26:39 +00:00
{
2012-02-01 03:47:56 +00:00
{ L " . " , & builtin_source , N_ ( L " Evaluate contents of file " ) } ,
{ L " and " , & builtin_generic , N_ ( L " Execute command if previous command suceeded " ) } ,
{ L " begin " , & builtin_begin , N_ ( L " Create a block of code " ) } ,
{ L " bg " , & builtin_bg , N_ ( L " Send job to background " ) } ,
{ L " bind " , & builtin_bind , N_ ( L " Handle fish key bindings " ) } ,
{ L " block " , & builtin_block , N_ ( L " Temporarily block delivery of events " ) } ,
{ L " break " , & builtin_break_continue , N_ ( L " Stop the innermost loop " ) } ,
{ L " breakpoint " , & builtin_breakpoint , N_ ( L " Temporarily halt execution of a script and launch an interactive debug prompt " ) } ,
{ L " builtin " , & builtin_builtin , N_ ( L " Run a builtin command instead of a function " ) } ,
{ L " case " , & builtin_case , N_ ( L " Conditionally execute a block of commands " ) } ,
{ L " cd " , & builtin_cd , N_ ( L " Change working directory " ) } ,
{ L " command " , & builtin_generic , N_ ( L " Run a program instead of a function or builtin " ) } ,
{ L " commandline " , & builtin_commandline , N_ ( L " Set or get the commandline " ) } ,
{ L " complete " , & builtin_complete , N_ ( L " Edit command specific completions " ) } ,
{ L " contains " , & builtin_contains , N_ ( L " Search for a specified string in a list " ) } ,
{ L " continue " , & builtin_break_continue , N_ ( L " Skip the rest of the current lap of the innermost loop " ) } ,
{ L " count " , & builtin_count , N_ ( L " Count the number of arguments " ) } ,
2012-03-07 19:35:22 +00:00
{ L " echo " , & builtin_echo , N_ ( L " Print arguments " ) } ,
2012-02-01 03:47:56 +00:00
{ L " else " , & builtin_else , N_ ( L " Evaluate block if condition is false " ) } ,
{ L " emit " , & builtin_emit , N_ ( L " Emit an event " ) } ,
{ L " end " , & builtin_end , N_ ( L " End a block of commands " ) } ,
{ L " exec " , & builtin_generic , N_ ( L " Run command in current process " ) } ,
{ L " exit " , & builtin_exit , N_ ( L " Exit the shell " ) } ,
{ L " fg " , & builtin_fg , N_ ( L " Send job to foreground " ) } ,
{ L " for " , & builtin_for , N_ ( L " Perform a set of commands multiple times " ) } ,
{ L " function " , & builtin_function , N_ ( L " Define a new function " ) } ,
{ L " functions " , & builtin_functions , N_ ( L " List or remove functions " ) } ,
{ L " if " , & builtin_generic , N_ ( L " Evaluate block if condition is true " ) } ,
{ L " jobs " , & builtin_jobs , N_ ( L " Print currently running jobs " ) } ,
{ L " not " , & builtin_generic , N_ ( L " Negate exit status of job " ) } ,
{ L " or " , & builtin_generic , N_ ( L " Execute command if previous command failed " ) } ,
2012-03-10 04:16:26 +00:00
{ L " pwd " , & builtin_pwd , N_ ( L " Print the working directory " ) } ,
2012-02-01 03:47:56 +00:00
{ L " random " , & builtin_random , N_ ( L " Generate random number " ) } ,
{ L " read " , & builtin_read , N_ ( L " Read a line of input into variables " ) } ,
{ L " return " , & builtin_return , N_ ( L " Stop the currently evaluated function " ) } ,
{ L " set " , & builtin_set , N_ ( L " Handle environment variables " ) } ,
{ L " status " , & builtin_status , N_ ( L " Return status information about fish " ) } ,
{ L " switch " , & builtin_switch , N_ ( L " Conditionally execute a block of commands " ) } ,
2012-03-07 08:54:01 +00:00
{ L " test " , & builtin_test , N_ ( L " Test a condition " ) } ,
2012-02-01 03:47:56 +00:00
{ L " ulimit " , & builtin_ulimit , N_ ( L " Set or get the shells resource usage limits " ) } ,
{ L " while " , & builtin_generic , N_ ( L " Perform a command multiple times " ) }
} ;
# define BUILTIN_COUNT (sizeof builtin_datas / sizeof *builtin_datas)
2012-02-01 04:22:25 +00:00
static const builtin_data_t * builtin_lookup ( const wcstring & name ) {
2012-02-01 03:47:56 +00:00
const builtin_data_t * array_end = builtin_datas + BUILTIN_COUNT ;
const builtin_data_t * found = std : : lower_bound ( builtin_datas , array_end , name ) ;
2012-02-01 04:22:25 +00:00
if ( found ! = array_end & & name = = found - > name ) {
2012-02-01 03:47:56 +00:00
return found ;
} else {
return NULL ;
}
2006-02-05 13:08:40 +00:00
}
2006-01-30 19:53:10 +00:00
2006-02-05 13:08:40 +00:00
void builtin_init ( )
{
2011-12-27 03:18:46 +00:00
2007-01-21 14:55:27 +00:00
wopterr = 0 ;
2012-02-01 03:47:56 +00:00
for ( size_t i = 0 ; i < BUILTIN_COUNT ; i + + )
2006-02-05 13:08:40 +00:00
{
2012-02-01 03:47:56 +00:00
intern_static ( builtin_datas [ i ] . name ) ;
2006-02-05 13:08:40 +00:00
}
2005-09-20 13:26:39 +00:00
}
void builtin_destroy ( )
{
}
2012-02-01 04:22:25 +00:00
int builtin_exists ( const wcstring & cmd )
2005-09-20 13:26:39 +00:00
{
2012-02-01 03:47:56 +00:00
return ! ! builtin_lookup ( cmd ) ;
2005-09-20 13:26:39 +00:00
}
/**
Return true if the specified builtin should handle it ' s own help ,
false otherwise .
*/
2012-01-30 06:06:58 +00:00
static int internal_help ( const wchar_t * cmd )
2005-09-20 13:26:39 +00:00
{
2006-10-28 16:44:48 +00:00
CHECK ( cmd , 0 ) ;
2007-10-02 10:09:37 +00:00
return contains ( cmd , L " for " , L " while " , L " function " ,
2010-11-26 11:00:18 +00:00
L " if " , L " end " , L " switch " , L " count " ) ;
2005-09-20 13:26:39 +00:00
}
2012-01-30 06:06:58 +00:00
int builtin_run ( parser_t & parser , const wchar_t * const * argv , io_data_t * io )
2005-09-20 13:26:39 +00:00
{
2012-01-30 06:06:58 +00:00
int ( * cmd ) ( parser_t & parser , const wchar_t * const * argv ) = 0 ;
2007-04-25 18:30:02 +00:00
real_io = io ;
2011-12-27 03:18:46 +00:00
2006-12-13 14:34:31 +00:00
CHECK ( argv , STATUS_BUILTIN_ERROR ) ;
CHECK ( argv [ 0 ] , STATUS_BUILTIN_ERROR ) ;
2012-02-01 03:47:56 +00:00
const builtin_data_t * data = builtin_lookup ( argv [ 0 ] ) ;
cmd = ( int ( * ) ( parser_t & parser , const wchar_t * const * ) ) ( data ? data - > func : NULL ) ;
2011-12-27 03:18:46 +00:00
2005-09-20 13:26:39 +00:00
if ( argv [ 1 ] ! = 0 & & ! internal_help ( argv [ 0 ] ) )
{
2012-01-19 18:28:44 +00:00
if ( argv [ 2 ] = = 0 & & ( parser . is_help ( argv [ 1 ] , 0 ) ) )
2005-09-20 13:26:39 +00:00
{
2012-02-22 18:51:06 +00:00
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_OK ;
2005-09-20 13:26:39 +00:00
}
}
2006-01-30 19:53:10 +00:00
2012-02-01 03:47:56 +00:00
if ( data ! = NULL )
2005-09-20 13:26:39 +00:00
{
int status ;
2006-01-30 19:53:10 +00:00
2012-01-19 18:28:44 +00:00
status = cmd ( parser , argv ) ;
2005-09-20 13:26:39 +00:00
return status ;
2006-01-30 19:53:10 +00:00
2005-09-20 13:26:39 +00:00
}
else
{
2006-01-04 12:51:02 +00:00
debug ( 0 , _ ( L " Unknown builtin '%ls' " ) , argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
}
2006-12-13 14:34:31 +00:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 13:26:39 +00:00
}
2012-02-01 03:47:56 +00:00
wcstring_list_t builtin_get_names ( void )
2005-09-20 13:26:39 +00:00
{
2012-02-01 03:47:56 +00:00
wcstring_list_t result ;
result . reserve ( BUILTIN_COUNT ) ;
for ( size_t i = 0 ; i < BUILTIN_COUNT ; i + + ) {
result . push_back ( builtin_datas [ i ] . name ) ;
}
return result ;
2005-09-20 13:26:39 +00:00
}
2012-02-01 03:47:56 +00:00
void builtin_get_names ( std : : vector < completion_t > & list ) {
for ( size_t i = 0 ; i < BUILTIN_COUNT ; i + + ) {
2012-02-02 00:27:14 +00:00
list . push_back ( completion_t ( builtin_datas [ i ] . name ) ) ;
2012-02-01 03:47:56 +00:00
}
2012-01-16 16:56:47 +00:00
}
2012-05-18 02:37:46 +00:00
wcstring builtin_get_desc ( const wcstring & name )
2005-09-20 13:26:39 +00:00
{
2012-05-18 02:37:46 +00:00
wcstring result ;
2012-02-01 03:47:56 +00:00
const builtin_data_t * builtin = builtin_lookup ( name ) ;
2012-05-18 02:37:46 +00:00
if ( builtin ) {
result = _ ( builtin - > desc ) ;
}
return result ;
2005-09-20 13:26:39 +00:00
}
2012-01-23 04:47:13 +00:00
void builtin_push_io ( parser_t & parser , int in )
2005-09-20 13:26:39 +00:00
{
2012-02-08 07:53:34 +00:00
ASSERT_IS_MAIN_THREAD ( ) ;
2005-09-20 13:26:39 +00:00
if ( builtin_stdin ! = - 1 )
{
2012-02-22 18:51:06 +00:00
struct io_stack_elem_t elem = { builtin_stdin , stdout_buffer , stderr_buffer } ;
2012-02-08 07:53:34 +00:00
io_stack . push ( elem ) ;
2005-09-20 13:26:39 +00:00
}
builtin_stdin = in ;
2012-02-22 18:51:06 +00:00
stdout_buffer . clear ( ) ;
stderr_buffer . clear ( ) ;
2005-09-20 13:26:39 +00:00
}
2012-01-23 05:40:08 +00:00
void builtin_pop_io ( parser_t & parser )
2005-09-20 13:26:39 +00:00
{
2012-02-08 07:53:34 +00:00
ASSERT_IS_MAIN_THREAD ( ) ;
2005-09-20 13:26:39 +00:00
builtin_stdin = 0 ;
2012-02-08 07:53:34 +00:00
if ( ! io_stack . empty ( ) )
2005-09-20 13:26:39 +00:00
{
2012-02-08 07:53:34 +00:00
struct io_stack_elem_t & elem = io_stack . top ( ) ;
2012-02-22 18:51:06 +00:00
stderr_buffer = elem . err ;
stdout_buffer = elem . out ;
2012-02-08 07:53:34 +00:00
builtin_stdin = elem . in ;
io_stack . pop ( ) ;
2005-09-20 13:26:39 +00:00
}
else
{
2012-02-22 18:51:06 +00:00
stdout_buffer . clear ( ) ;
stderr_buffer . clear ( ) ;
2005-09-20 13:26:39 +00:00
builtin_stdin = 0 ;
}
}