2005-09-20 21:26:39 +08: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-31 03:53:10 +08:00
where NAME is the name of the builtin , and args is a zero - terminated list of arguments .
2005-09-20 21:26:39 +08:00
2006-02-06 05:20:50 +08:00
2 ) . Add a line like { L " NAME " , & builtin_NAME , N_ ( L " Bla bla bla " ) } , to the builtin_data variable . The description is used by the completion system .
2005-09-20 21:26:39 +08:00
2006-02-06 05:20:50 +08: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 21:26:39 +08:00
2006-02-06 05:20:50 +08:00
4 ) . Add an entry to the BUILTIN_DOC_SRC variable of Makefile . in . Note that the entries should be sorted alphabetically !
2006-01-31 03:53:10 +08:00
2006-06-17 21:07:08 +08:00
5 ) . Add an entry to the manual at the builtin - overview subsection of doc_src / doc . hdr . Note that the entries should be sorted alphabetically !
2005-09-20 21:26:39 +08:00
2006-02-06 05:20:50 +08:00
6 ) . Use ' darcs add doc_src / NAME . txt ' to start tracking changes to the documentation file .
2005-12-15 07:48:08 +08:00
2005-09-20 21:26:39 +08:00
*/
2006-08-11 09:18:35 +08:00
# include "config.h"
2005-09-20 21:26:39 +08: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-25 03:55:58 +08:00
# include <time.h>
2005-09-20 21:26:39 +08:00
2006-02-28 21:17:16 +08:00
# include "fallback.h"
2005-09-20 21:26:39 +08:00
# include "util.h"
2006-02-28 21:17:16 +08:00
2005-09-20 21:26:39 +08: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-06 06:37:08 +08:00
# include "event.h"
2005-10-08 19:20:51 +08:00
# include "signal.h"
2006-07-20 06:55:49 +08:00
2006-02-06 23:18:17 +08:00
# include "halloc.h"
2006-02-09 23:50:20 +08:00
# include "halloc_util.h"
2006-02-15 03:56:36 +08:00
# include "parse_util.h"
# include "expand.h"
2006-10-19 19:50:23 +08:00
# include "path.h"
2005-09-20 21:26:39 +08:00
2006-06-21 05:20:16 +08:00
2006-06-13 21:43:28 +08:00
2005-09-20 21:26:39 +08: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 21:59:02 +08:00
2005-09-20 21:26:39 +08:00
/**
2005-12-15 21:59:02 +08:00
The send stuff to foreground message
2005-09-20 21:26:39 +08:00
*/
2006-01-04 20:51:02 +08:00
# define FG_MSG _( L"Send job %d, '%ls' to foreground\n" )
2005-12-12 07:30:01 +08:00
2006-06-17 21:07:08 +08:00
/**
Datastructure to describe a builtin .
*/
2006-02-05 21:08:40 +08:00
typedef struct builtin_data
{
2006-06-17 21:07:08 +08:00
/**
Name of the builtin
*/
2006-02-05 21:08:40 +08:00
const wchar_t * name ;
2006-06-17 21:07:08 +08:00
/**
Function pointer tothe builtin implementation
*/
2006-02-05 21:08:40 +08:00
int ( * func ) ( wchar_t * * argv ) ;
2006-06-17 21:07:08 +08:00
/**
Description of what the builtin does
*/
2006-02-05 21:08:40 +08:00
const wchar_t * desc ;
}
builtin_data_t ;
2005-12-15 21:59:02 +08:00
/**
Table of all builtins
*/
2005-09-20 21:26:39 +08:00
static hash_table_t builtin ;
int builtin_out_redirect ;
int builtin_err_redirect ;
2005-12-15 21:59:02 +08:00
/*
2006-02-06 05:20:50 +08:00
Buffers for storing the output of builtin functions
2005-09-20 21:26:39 +08:00
*/
string_buffer_t * sb_out = 0 , * sb_err = 0 ;
2005-12-15 21:59:02 +08:00
2005-09-20 21:26:39 +08:00
/**
Stack containing builtin I / O for recursive builtin calls .
*/
static array_list_t io_stack ;
2006-01-31 03:53:10 +08:00
/**
2006-02-06 05:20:50 +08:00
The file from which builtin functions should attempt to read , use
instead of stdin .
2005-09-20 21:26:39 +08:00
*/
static int builtin_stdin ;
/**
Table containing descriptions for all builtins
*/
static hash_table_t * desc = 0 ;
2006-06-21 05:20:16 +08:00
/**
Counts the number of non null pointers in the specified array
*/
static int builtin_count_args ( wchar_t * * argv )
2005-09-20 21:26:39 +08:00
{
int argc = 1 ;
while ( argv [ argc ] ! = 0 )
{
argc + + ;
}
return argc ;
}
2006-06-21 05:20:16 +08:00
/**
This function works like wperror , but it prints its result into
the sb_err string_buffer_t instead of to stderr . Used by the builtin
commands .
*/
2005-10-15 06:33:01 +08:00
2006-06-21 05:20:16 +08:00
static void builtin_wperror ( const wchar_t * s )
2005-09-20 21:26:39 +08:00
{
if ( s ! = 0 )
{
2005-10-01 02:28:26 +08:00
sb_append2 ( sb_err , s , L " : " , ( void * ) 0 ) ;
2005-09-20 21:26:39 +08:00
}
char * err = strerror ( errno ) ;
wchar_t * werr = str2wcs ( err ) ;
if ( werr )
{
2006-01-31 03:53:10 +08:00
sb_append2 ( sb_err , werr , L " \n " , ( void * ) 0 ) ;
2005-09-20 21:26:39 +08:00
free ( werr ) ;
2006-01-31 03:53:10 +08:00
}
2005-09-20 21:26:39 +08:00
}
2006-06-17 21:07:08 +08:00
/**
Count the number of times the specified character occurs in the specified string
*/
2006-05-26 19:24:02 +08: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 21:26:39 +08:00
2006-06-21 05:20:16 +08:00
/**
Print help for the specified builtin . If \ c b is sb_err , also print
the line information
2006-06-09 07:55:57 +08:00
2006-06-21 05:20:16 +08:00
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 .
2005-09-20 21:26:39 +08:00
2006-05-26 19:24:02 +08:00
*/
2005-09-20 21:26:39 +08:00
2006-06-21 05:20:16 +08:00
static void builtin_print_help ( wchar_t * cmd , string_buffer_t * b )
2005-09-20 21:26:39 +08:00
{
const char * h ;
if ( b = = sb_err )
{
2006-01-31 03:53:10 +08:00
sb_append ( sb_err ,
2005-09-20 21:26:39 +08:00
parser_current_line ( ) ) ;
}
h = builtin_help_get ( cmd ) ;
if ( ! h )
return ;
2006-05-26 19:24:02 +08:00
wchar_t * str = str2wcs ( h ) ;
2005-09-20 21:26:39 +08:00
if ( str )
{
2006-05-26 19:24:02 +08:00
if ( is_interactive & & ! builtin_out_redirect & & b = = sb_err )
{
/* Interactive mode help to screen - only print synopsis if the rest won't fit */
int screen_height , lines ;
screen_height = common_get_height ( ) ;
lines = count_char ( str , L ' \n ' ) ;
if ( lines > 2 * screen_height / 3 )
{
wchar_t * pos ;
/* Find first empty line */
for ( pos = str ; * pos ; pos + + )
{
if ( * pos = = L ' \n ' )
{
wchar_t * pos2 ;
int is_empty = 1 ;
for ( pos2 = pos + 1 ; * pos2 ; pos2 + + )
{
if ( * pos2 = = L ' \n ' )
break ;
if ( * pos2 ! = L ' \t ' & & * pos2 ! = L ' ' )
{
is_empty = 0 ;
break ;
}
}
if ( is_empty )
{
* ( pos + 1 ) = L ' \0 ' ;
}
}
}
}
}
2005-09-20 21:26:39 +08:00
sb_append ( b , str ) ;
free ( str ) ;
}
}
2006-06-21 05:20:16 +08: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
' builtin_NAME . c ' , where NAME is the name of the builtin .
*/
# include "builtin_help.c"
# include "builtin_set.c"
# include "builtin_commandline.c"
# include "builtin_complete.c"
# include "builtin_ulimit.c"
# include "builtin_jobs.c"
2005-09-20 21:26:39 +08:00
/**
The bind builtin , used for setting character sequences
*/
static int builtin_bind ( wchar_t * * argv )
{
int i ;
int argc = builtin_count_args ( argv ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
2006-01-31 03:53:10 +08:00
L " set-mode " , required_argument , 0 , ' M '
2005-09-20 21:26:39 +08:00
}
,
2006-05-26 19:24:02 +08:00
{
L " help " , no_argument , 0 , ' h '
}
,
2006-01-31 03:53:10 +08:00
{
0 , 0 , 0 , 0
2005-09-20 21:26:39 +08:00
}
}
2006-01-31 03:53:10 +08:00
;
2005-09-20 21:26:39 +08:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int opt = wgetopt_long ( argc ,
2006-01-31 03:53:10 +08:00
argv ,
2006-05-26 19:24:02 +08:00
L " M:h " ,
2006-01-31 03:53:10 +08:00
long_options ,
2005-09-20 21:26:39 +08:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
2006-01-04 20:51:02 +08:00
argv [ 0 ] ,
2006-01-31 03:53:10 +08:00
long_options [ opt_index ] . name ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
case ' M ' :
2005-09-20 21:26:39 +08:00
input_set_mode ( woptarg ) ;
break ;
2006-05-26 19:24:02 +08:00
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_out ) ;
return 0 ;
2005-09-20 21:26:39 +08:00
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
}
2005-09-20 21:26:39 +08:00
for ( i = woptind ; i < argc ; i + + )
{
2006-01-31 03:53:10 +08:00
input_parse_inputrc_line ( argv [ i ] ) ;
2005-09-20 21:26:39 +08:00
}
return 0 ;
}
2006-01-31 03:53:10 +08:00
/**
2006-02-06 05:20:50 +08:00
The block builtin , used for temporarily blocking events
*/
2005-12-12 06:21:01 +08:00
static int builtin_block ( wchar_t * * argv )
{
enum
{
UNSET ,
GLOBAL ,
LOCAL ,
}
;
int scope = UNSET ;
int erase = 0 ;
int argc = builtin_count_args ( argv ) ;
2006-01-31 03:53:10 +08:00
int type = ( 1 < < EVENT_ANY ) ;
2005-12-12 06:21:01 +08:00
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
2006-01-31 03:53:10 +08:00
L " erase " , no_argument , 0 , ' e '
2005-12-12 06:21:01 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " local " , no_argument , 0 , ' l '
2005-12-12 06:21:01 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " global " , no_argument , 0 , ' g '
2005-12-12 06:21:01 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " help " , no_argument , 0 , ' h '
2005-12-12 06:21:01 +08:00
}
,
2006-01-31 03:53:10 +08:00
{
0 , 0 , 0 , 0
2005-12-12 06:21:01 +08:00
}
}
2006-01-31 03:53:10 +08:00
;
2005-12-12 06:21:01 +08:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
int opt = wgetopt_long ( argc ,
2006-01-31 03:53:10 +08:00
argv ,
L " elgh " ,
long_options ,
2005-12-12 06:21:01 +08:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
2006-01-31 03:53:10 +08:00
long_options [ opt_index ] . name ) ;
2005-12-12 06:21:01 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-12-12 06:21:01 +08:00
case ' h ' :
2006-05-26 19:24:02 +08:00
builtin_print_help ( argv [ 0 ] , sb_out ) ;
2005-12-12 06:21:01 +08:00
return 0 ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
case ' g ' :
scope = GLOBAL ;
break ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
case ' l ' :
scope = LOCAL ;
break ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
case ' e ' :
erase = 1 ;
break ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
}
2006-01-31 03:53:10 +08:00
}
2005-12-12 06:21:01 +08:00
if ( erase )
{
if ( scope ! = UNSET )
{
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err , _ ( L " %ls: Can not specify scope when removing block \n " ) , argv [ 0 ] ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-12-12 06:21:01 +08:00
}
if ( ! global_event_block )
{
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err , _ ( L " %ls: No blocks defined \n " ) , argv [ 0 ] ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-12-12 06:21:01 +08:00
}
event_block_t * eb = global_event_block ;
global_event_block = eb - > next ;
free ( eb ) ;
}
else
{
block_t * block = current_block ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
event_block_t * eb = malloc ( sizeof ( event_block_t ) ) ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
if ( ! eb )
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
eb - > type = type ;
switch ( scope )
{
case LOCAL :
{
if ( ! block - > outer )
block = 0 ;
break ;
}
case GLOBAL :
{
block = 0 ;
}
case UNSET :
{
while ( block & & block - > type ! = FUNCTION_CALL )
block = block - > outer ;
}
}
if ( block )
{
eb - > next = block - > first_event_block ;
block - > first_event_block = eb ;
2006-02-07 02:11:01 +08:00
halloc_register ( block , eb ) ;
2005-12-12 06:21:01 +08:00
}
else
{
eb - > next = global_event_block ;
global_event_block = eb ;
2006-01-31 03:53:10 +08:00
}
2005-12-12 06:21:01 +08:00
}
return 0 ;
2006-01-31 03:53:10 +08:00
2005-12-12 06:21:01 +08:00
}
2005-09-20 21:26:39 +08:00
/**
The builtin builtin , used for given builtins precedence over functions . Mostly handled by the parser . All this code does is some additional operational modes , such as printing a list of all builtins .
*/
static int builtin_builtin ( wchar_t * * argv )
{
int argc = builtin_count_args ( argv ) ;
int list = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
2006-01-31 03:53:10 +08:00
L " names " , no_argument , 0 , ' n '
2005-09-20 21:26:39 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " help " , no_argument , 0 , ' h '
2005-09-20 21:26:39 +08:00
}
,
2006-01-31 03:53:10 +08:00
{
0 , 0 , 0 , 0
2005-09-20 21:26:39 +08:00
}
}
2006-01-31 03:53:10 +08:00
;
2005-09-20 21:26:39 +08:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int opt = wgetopt_long ( argc ,
2006-01-31 03:53:10 +08:00
argv ,
L " nh " ,
long_options ,
2005-09-20 21:26:39 +08:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
case ' h ' :
2006-05-26 19:24:02 +08:00
builtin_print_help ( argv [ 0 ] , sb_out ) ;
2005-09-20 21:26:39 +08:00
return 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
case ' n ' :
list = 1 ;
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
}
2005-09-20 21:26:39 +08:00
if ( list )
{
array_list_t names ;
int i ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
al_init ( & names ) ;
builtin_get_names ( & names ) ;
2006-05-14 17:47:21 +08:00
sort_list ( & names ) ;
2005-09-20 21:26:39 +08:00
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
2006-05-14 17:47:21 +08:00
wchar_t * el = ( wchar_t * ) al_get ( & names , i ) ;
if ( wcscmp ( el , L " count " ) = = 0 )
2005-09-20 21:26:39 +08:00
continue ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
sb_append2 ( sb_out ,
2006-05-14 17:47:21 +08:00
el ,
2005-09-20 21:26:39 +08:00
L " \n " ,
2006-01-31 03:53:10 +08:00
( void * ) 0 ) ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
al_destroy ( & names ) ;
}
2005-09-20 21:26:39 +08:00
return 0 ;
}
/**
A generic bultin that only supports showing a help message . This is
only a placeholder that prints the help message . Useful for
commands that live in hte parser .
*/
static int builtin_generic ( wchar_t * * argv )
{
int argc = builtin_count_args ( argv ) ;
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
L " help " , no_argument , 0 , ' h '
}
,
2006-01-31 03:53:10 +08:00
{
0 , 0 , 0 , 0
2005-09-20 21:26:39 +08:00
}
}
2006-01-31 03:53:10 +08:00
;
2005-09-20 21:26:39 +08:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int opt = wgetopt_long ( argc ,
2006-01-31 03:53:10 +08:00
argv ,
L " h " ,
long_options ,
2005-09-20 21:26:39 +08:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_out ) ;
2006-01-31 03:53:10 +08:00
return 0 ;
2005-09-20 21:26:39 +08:00
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
}
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
/**
2006-09-08 22:12:41 +08:00
Output a definition of the specified function to the specified
2006-01-24 04:40:14 +08:00
stringbuffer . Used by the functions builtin .
*/
2006-09-08 22:12:41 +08:00
static void functions_def ( wchar_t * name , string_buffer_t * out )
2005-12-17 20:25:46 +08:00
{
const wchar_t * desc = function_get_desc ( name ) ;
const wchar_t * def = function_get_definition ( name ) ;
2006-01-31 03:53:10 +08:00
2005-12-17 20:25:46 +08:00
array_list_t ev ;
event_t search ;
2006-01-24 07:33:47 +08:00
2005-12-17 20:25:46 +08:00
int i ;
2006-01-24 07:33:47 +08:00
2005-12-17 20:25:46 +08:00
search . function_name = name ;
search . type = EVENT_ANY ;
2006-01-24 07:33:47 +08:00
2005-12-17 20:25:46 +08:00
al_init ( & ev ) ;
event_get ( & search , & ev ) ;
2006-01-24 07:33:47 +08:00
2006-09-08 22:12:41 +08:00
sb_append2 ( out ,
2005-12-17 20:25:46 +08:00
L " function " ,
name ,
( void * ) 0 ) ;
if ( desc & & wcslen ( desc ) )
{
wchar_t * esc_desc = escape ( desc , 1 ) ;
2006-01-31 03:53:10 +08:00
2006-09-08 22:12:41 +08:00
sb_append2 ( out , L " --description " , esc_desc , ( void * ) 0 ) ;
2005-12-17 20:25:46 +08:00
free ( esc_desc ) ;
}
2006-01-24 07:33:47 +08:00
2005-12-17 20:25:46 +08:00
for ( i = 0 ; i < al_get_count ( & ev ) ; i + + )
{
event_t * next = ( event_t * ) al_get ( & ev , i ) ;
switch ( next - > type )
{
case EVENT_SIGNAL :
{
2006-09-08 22:12:41 +08:00
sb_printf ( out , L " --on-signal %ls " , sig2wcs ( next - > param1 . signal ) ) ;
2005-12-17 20:25:46 +08:00
break ;
}
2006-01-24 07:33:47 +08:00
2005-12-17 20:25:46 +08:00
case EVENT_VARIABLE :
{
2006-09-08 22:12:41 +08:00
sb_printf ( out , L " --on-variable %ls " , next - > param1 . variable ) ;
2005-12-17 20:25:46 +08:00
break ;
}
case EVENT_EXIT :
{
if ( next - > param1 . pid > 0 )
2006-09-08 22:12:41 +08:00
sb_printf ( out , L " --on-process-exit %d " , next - > param1 . pid ) ;
2005-12-17 20:25:46 +08:00
else
2006-09-08 22:12:41 +08:00
sb_printf ( out , L " --on-job-exit %d " , - next - > param1 . pid ) ;
2005-12-17 20:25:46 +08:00
break ;
}
case EVENT_JOB_ID :
{
job_t * j = job_get ( next - > param1 . job_id ) ;
if ( j )
2006-09-08 22:12:41 +08:00
sb_printf ( out , L " --on-job-exit %d " , j - > pgid ) ;
2005-12-17 20:25:46 +08:00
break ;
}
}
2006-01-31 03:53:10 +08:00
2006-01-24 07:33:47 +08:00
}
2005-12-17 20:25:46 +08:00
al_destroy ( & ev ) ;
2006-01-24 07:33:47 +08:00
2006-09-08 22:12:41 +08:00
sb_append2 ( out ,
2005-12-17 20:25:46 +08:00
L " \n \t " ,
def ,
L " \n end \n \n " ,
( void * ) 0 ) ;
2006-01-24 07:33:47 +08:00
2005-12-17 20:25:46 +08:00
}
2005-09-20 21:26:39 +08:00
/**
The functions builtin , used for listing and erasing functions .
*/
static int builtin_functions ( wchar_t * * argv )
{
int i ;
int erase = 0 ;
2006-01-31 03:53:10 +08:00
wchar_t * desc = 0 ;
2005-09-20 21:26:39 +08:00
array_list_t names ;
int argc = builtin_count_args ( argv ) ;
int list = 0 ;
2006-01-31 03:53:10 +08:00
int show_hidden = 0 ;
2005-10-15 08:51:26 +08:00
int res = 0 ;
2006-07-13 01:46:55 +08:00
int query = 0 ;
2006-01-24 07:33:47 +08:00
2005-09-20 21:26:39 +08:00
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
2006-01-31 03:53:10 +08:00
L " erase " , no_argument , 0 , ' e '
2005-09-20 21:26:39 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " description " , required_argument , 0 , ' d '
2005-09-20 21:26:39 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " names " , no_argument , 0 , ' n '
2005-09-20 21:26:39 +08:00
}
,
{
L " all " , no_argument , 0 , ' a '
}
,
2006-05-26 19:24:02 +08:00
{
L " help " , no_argument , 0 , ' h '
}
,
2006-07-13 01:46:55 +08:00
{
L " query " , no_argument , 0 , ' q '
}
,
2006-01-31 03:53:10 +08:00
{
0 , 0 , 0 , 0
2005-09-20 21:26:39 +08:00
}
}
2006-01-31 03:53:10 +08:00
;
2005-09-20 21:26:39 +08:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-24 07:33:47 +08:00
2005-09-20 21:26:39 +08:00
int opt = wgetopt_long ( argc ,
2006-01-31 03:53:10 +08:00
argv ,
2006-07-13 01:46:55 +08:00
L " ed:nahq " ,
2006-01-31 03:53:10 +08:00
long_options ,
2005-09-20 21:26:39 +08:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-24 07:33:47 +08:00
2005-09-20 21:26:39 +08:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
case ' e ' :
erase = 1 ;
2005-09-20 21:26:39 +08:00
break ;
case ' d ' :
desc = woptarg ;
2006-01-31 03:53:10 +08:00
break ;
2005-09-20 21:26:39 +08:00
case ' n ' :
list = 1 ;
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
case ' a ' :
show_hidden = 1 ;
break ;
2006-01-31 03:53:10 +08:00
2006-05-26 19:24:02 +08:00
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_out ) ;
return 0 ;
2006-07-13 01:46:55 +08:00
case ' q ' :
query = 1 ;
break ;
2005-09-20 21:26:39 +08:00
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
2006-01-24 07:33:47 +08:00
}
2005-09-20 21:26:39 +08:00
/*
2006-07-13 01:46:55 +08:00
Erase , desc , query and list are mutually exclusive
2005-09-20 21:26:39 +08:00
*/
2006-07-13 01:46:55 +08:00
if ( ( erase + ( desc ! = 0 ) + list + query ) > 1 )
2005-09-20 21:26:39 +08:00
{
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
_ ( L " %ls: Invalid combination of options \n " ) ,
argv [ 0 ] ) ;
2006-01-24 07:33:47 +08:00
2006-01-04 20:51:02 +08:00
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-24 07:33:47 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
if ( erase )
{
int i ;
for ( i = woptind ; i < argc ; i + + )
function_remove ( argv [ i ] ) ;
return 0 ;
}
else if ( desc )
{
wchar_t * func ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( argc - woptind ! = 1 )
{
2005-12-15 21:59:02 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Expected exactly one function name \n " ) ,
2006-01-31 03:53:10 +08:00
argv [ 0 ] ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
func = argv [ woptind ] ;
if ( ! function_exists ( func ) )
{
2005-12-15 21:59:02 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Function '%ls' does not exist \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ,
func ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
function_set_desc ( func , desc ) ;
return 0 ;
2005-09-20 21:26:39 +08:00
}
else if ( list )
{
2006-01-15 19:58:05 +08:00
int is_screen = ! builtin_out_redirect & & isatty ( 1 ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
al_init ( & names ) ;
function_get_names ( & names , show_hidden ) ;
2006-05-14 17:47:21 +08:00
sort_list ( & names ) ;
2006-01-15 19:58:05 +08:00
if ( is_screen )
2005-09-20 21:26:39 +08:00
{
2006-01-15 19:58:05 +08:00
string_buffer_t buff ;
sb_init ( & buff ) ;
2006-01-31 03:53:10 +08:00
2006-01-15 19:58:05 +08:00
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
sb_append2 ( & buff ,
2006-05-14 17:47:21 +08:00
al_get ( & names , i ) ,
2006-01-15 19:58:05 +08:00
L " , " ,
2006-01-31 03:53:10 +08:00
( void * ) 0 ) ;
2006-01-15 19:58:05 +08:00
}
2006-01-31 03:53:10 +08:00
2006-05-14 17:47:21 +08:00
write_screen ( ( wchar_t * ) buff . buff , sb_out ) ;
2006-01-15 19:58:05 +08:00
sb_destroy ( & buff ) ;
}
else
{
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
sb_append2 ( sb_out ,
2006-05-14 17:47:21 +08:00
al_get ( & names , i ) ,
2006-01-15 19:58:05 +08:00
L " \n " ,
2006-01-31 03:53:10 +08:00
( void * ) 0 ) ;
2006-01-15 19:58:05 +08:00
}
2005-09-20 21:26:39 +08:00
}
2006-01-25 02:14:10 +08:00
2006-01-31 03:53:10 +08:00
al_destroy ( & names ) ;
2005-09-20 21:26:39 +08:00
return 0 ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( argc - woptind )
{
case 0 :
{
2006-07-13 01:46:55 +08:00
if ( ! query )
2005-09-20 21:26:39 +08:00
{
2006-07-13 01:46:55 +08:00
sb_append ( sb_out , _ ( L " Current function definitions are: \n \n " ) ) ;
al_init ( & names ) ;
function_get_names ( & names , show_hidden ) ;
sort_list ( & names ) ;
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
2006-09-08 22:12:41 +08:00
functions_def ( ( wchar_t * ) al_get ( & names , i ) , sb_out ) ;
2006-07-13 01:46:55 +08:00
}
al_destroy ( & names ) ;
2005-09-20 21:26:39 +08:00
}
2006-05-14 17:47:21 +08:00
2005-09-20 21:26:39 +08:00
break ;
}
2006-01-25 02:14:10 +08:00
2005-09-20 21:26:39 +08:00
default :
{
for ( i = woptind ; i < argc ; i + + )
2005-10-15 08:51:26 +08:00
{
if ( ! function_exists ( argv [ i ] ) )
res + + ;
else
{
2006-07-13 01:46:55 +08:00
if ( ! query )
{
2006-09-08 22:12:41 +08:00
functions_def ( argv [ i ] , sb_out ) ;
2006-07-13 01:46:55 +08:00
}
}
2005-10-15 08:51:26 +08:00
}
2006-01-25 02:14:10 +08:00
2005-09-20 21:26:39 +08:00
break ;
}
}
2005-10-15 08:51:26 +08:00
return res ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
2005-09-21 07:42:00 +08:00
/**
Test whether the specified string is a valid name for a keybinding
*/
static int wcsbindingname ( wchar_t * str )
2006-01-31 03:53:10 +08:00
{
2005-09-21 07:42:00 +08:00
while ( * str )
{
if ( ( ! iswalnum ( * str ) ) & & ( * str ! = L ' - ' ) )
{
return 0 ;
}
str + + ;
}
return 1 ;
}
2005-09-20 21:26:39 +08:00
2006-09-08 22:12:41 +08:00
typedef struct function_data
{
wchar_t * name ;
wchar_t * description ;
int is_binding ;
int do_save ;
array_list_t * events ;
}
function_data_t ;
2005-10-15 08:51:26 +08:00
2005-09-20 21:26:39 +08:00
/**
The function builtin , used for providing subroutines .
It calls various functions from function . c to perform any heavy lifting .
*/
static int builtin_function ( wchar_t * * argv )
2006-01-31 03:53:10 +08:00
{
2005-09-20 21:26:39 +08:00
int argc = builtin_count_args ( argv ) ;
int res = 0 ;
2006-01-31 03:53:10 +08:00
wchar_t * desc = 0 ;
2005-09-21 07:42:00 +08:00
int is_binding = 0 ;
2006-09-08 22:12:41 +08:00
int do_save = 0 ;
2006-02-07 02:11:01 +08:00
array_list_t * events ;
int i ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
woptind = 0 ;
2006-02-07 02:11:01 +08:00
parser_push_block ( FUNCTION_DEF ) ;
2006-02-09 23:50:20 +08:00
events = al_halloc ( current_block ) ;
2006-02-07 02:11:01 +08:00
2005-09-20 21:26:39 +08:00
const static struct woption
long_options [ ] =
{
{
2006-01-31 03:53:10 +08:00
L " description " , required_argument , 0 , ' d '
2005-09-20 21:26:39 +08:00
}
,
2005-09-21 07:42:00 +08:00
{
2006-01-31 03:53:10 +08:00
L " key-binding " , no_argument , 0 , ' b '
2005-09-21 07:42:00 +08:00
}
,
2005-10-06 06:37:08 +08:00
{
2006-01-31 03:53:10 +08:00
L " on-signal " , required_argument , 0 , ' s '
2005-10-06 06:37:08 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " on-job-exit " , required_argument , 0 , ' j '
2005-10-12 03:23:43 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " on-process-exit " , required_argument , 0 , ' p '
2005-10-06 06:37:08 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " on-variable " , required_argument , 0 , ' v '
2005-10-06 06:37:08 +08:00
}
,
2006-05-26 19:24:02 +08:00
{
L " help " , no_argument , 0 , ' h '
}
,
2006-09-08 22:12:41 +08:00
{
L " save " , no_argument , 0 , ' S '
}
,
2006-01-31 03:53:10 +08:00
{
0 , 0 , 0 , 0
2005-09-20 21:26:39 +08:00
}
}
2006-01-31 03:53:10 +08:00
;
2005-10-06 06:37:08 +08:00
while ( 1 & & ( ! res ) )
2005-09-20 21:26:39 +08:00
{
int opt_index = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int opt = wgetopt_long ( argc ,
2006-01-31 03:53:10 +08:00
argv ,
2006-09-08 22:12:41 +08:00
L " bd:s:j:p:v:hS " ,
2006-01-31 03:53:10 +08:00
long_options ,
2005-09-20 21:26:39 +08:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-25 02:14:10 +08:00
2005-10-06 06:37:08 +08:00
res = 1 ;
2006-01-31 03:53:10 +08:00
break ;
case ' d ' :
desc = woptarg ;
2005-09-20 21:26:39 +08:00
break ;
2005-09-21 07:42:00 +08:00
case ' b ' :
is_binding = 1 ;
break ;
2006-01-31 03:53:10 +08:00
2005-10-06 06:37:08 +08:00
case ' s ' :
{
2005-10-06 19:54:16 +08:00
int sig = wcs2sig ( woptarg ) ;
event_t * e ;
2006-01-31 03:53:10 +08:00
2005-10-06 19:54:16 +08:00
if ( sig < 0 )
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Unknown signal '%ls' \n " ) ,
2005-10-06 19:54:16 +08:00
argv [ 0 ] ,
woptarg ) ;
res = 1 ;
break ;
}
2006-01-31 03:53:10 +08:00
2006-02-07 02:11:01 +08:00
e = halloc ( current_block , sizeof ( event_t ) ) ;
2005-10-06 06:37:08 +08:00
if ( ! e )
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2005-10-06 06:37:08 +08:00
e - > type = EVENT_SIGNAL ;
2005-10-12 03:31:16 +08:00
e - > param1 . signal = sig ;
2006-01-31 03:53:10 +08:00
e - > function_name = 0 ;
2005-10-06 06:37:08 +08:00
al_push ( events , e ) ;
2006-01-31 03:53:10 +08:00
break ;
2005-10-06 06:37:08 +08:00
}
2006-01-31 03:53:10 +08:00
2005-10-06 06:37:08 +08:00
case ' v ' :
{
2005-10-06 19:54:16 +08:00
event_t * e ;
2006-04-21 22:29:39 +08:00
if ( wcsvarname ( woptarg ) )
2005-10-06 19:54:16 +08:00
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Invalid variable name '%ls' \n " ) ,
2005-10-06 19:54:16 +08:00
argv [ 0 ] ,
woptarg ) ;
res = 1 ;
break ;
}
2006-01-31 03:53:10 +08:00
2006-02-07 02:11:01 +08:00
e = halloc ( current_block , sizeof ( event_t ) ) ;
2005-10-06 06:37:08 +08:00
if ( ! e )
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2005-10-06 06:37:08 +08:00
e - > type = EVENT_VARIABLE ;
2006-02-11 08:13:17 +08:00
e - > param1 . variable = halloc_wcsdup ( current_block , woptarg ) ;
2006-01-31 03:53:10 +08:00
e - > function_name = 0 ;
2005-10-06 06:37:08 +08:00
al_push ( events , e ) ;
break ;
}
2006-01-31 03:53:10 +08:00
2005-10-12 03:23:43 +08:00
case ' j ' :
case ' p ' :
2005-10-06 06:37:08 +08:00
{
2005-10-06 19:54:16 +08:00
pid_t pid ;
wchar_t * end ;
event_t * e ;
2006-01-31 03:53:10 +08:00
2006-02-07 02:11:01 +08:00
e = halloc ( current_block , sizeof ( event_t ) ) ;
2005-10-06 06:37:08 +08:00
if ( ! e )
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2006-02-07 02:11:01 +08:00
2006-01-31 03:53:10 +08:00
if ( ( opt = = ' j ' ) & &
2005-10-15 08:51:26 +08:00
( wcscasecmp ( woptarg , L " caller " ) = = 0 ) )
{
int job_id = - 1 ;
2006-01-31 03:53:10 +08:00
if ( is_subshell )
2005-10-15 08:51:26 +08:00
{
block_t * b = current_block ;
2006-01-31 03:53:10 +08:00
2005-10-15 08:51:26 +08:00
while ( b & & ( b - > type ! = SUBST ) )
b = b - > outer ;
2006-01-31 03:53:10 +08:00
2005-10-15 08:51:26 +08:00
if ( b )
{
b = b - > outer ;
}
if ( b - > job )
{
job_id = b - > job - > job_id ;
}
}
2006-01-31 03:53:10 +08:00
2005-10-15 08:51:26 +08:00
if ( job_id = = - 1 )
{
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Cannot find calling job for event handler \n " ) ,
2005-10-15 08:51:26 +08:00
argv [ 0 ] ) ;
res = 1 ;
}
else
{
e - > type = EVENT_JOB_ID ;
e - > param1 . job_id = job_id ;
}
2006-01-31 03:53:10 +08:00
2005-10-15 08:51:26 +08:00
}
else
{
errno = 0 ;
2006-01-31 03:53:10 +08:00
pid = wcstol ( woptarg , & end , 10 ) ;
2005-10-15 08:51:26 +08:00
if ( errno | | ! end | | * end )
{
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Invalid process id %ls \n " ) ,
2005-10-15 08:51:26 +08:00
argv [ 0 ] ,
woptarg ) ;
res = 1 ;
break ;
2006-01-31 03:53:10 +08:00
}
2005-10-15 08:51:26 +08:00
e - > type = EVENT_EXIT ;
e - > param1 . pid = ( opt = = ' j ' ? - 1 : 1 ) * abs ( pid ) ;
}
if ( res )
{
free ( e ) ;
}
else
{
2006-01-31 03:53:10 +08:00
e - > function_name = 0 ;
2005-10-15 08:51:26 +08:00
al_push ( events , e ) ;
}
2006-01-31 03:53:10 +08:00
break ;
2005-10-06 06:37:08 +08:00
}
2006-01-31 03:53:10 +08:00
2006-09-08 22:12:41 +08:00
case ' S ' :
do_save = 1 ;
break ;
2006-05-26 19:24:02 +08:00
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_out ) ;
return 0 ;
2005-09-20 21:26:39 +08:00
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
res = 1 ;
2005-10-06 06:37:08 +08:00
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
}
2005-10-06 06:37:08 +08:00
if ( ! res )
2006-01-31 03:53:10 +08:00
{
2005-10-06 06:37:08 +08:00
if ( argc - woptind ! = 1 )
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Expected one argument, got %d \n " ) ,
2005-10-06 06:37:08 +08:00
argv [ 0 ] ,
argc - woptind ) ;
res = 1 ;
}
2006-04-21 22:29:39 +08:00
else if ( ! ( is_binding ? wcsbindingname ( argv [ woptind ] ) : ! wcsvarname ( argv [ woptind ] ) ) )
2006-01-31 03:53:10 +08:00
{
sb_printf ( sb_err ,
_ ( L " %ls: Illegal function name '%ls' \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ,
argv [ woptind ] ) ;
2006-01-31 03:53:10 +08:00
res = 1 ;
}
2005-10-06 06:37:08 +08:00
else if ( parser_is_reserved ( argv [ woptind ] ) )
{
2006-01-31 03:53:10 +08:00
2005-12-15 21:59:02 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: The name '%ls' is reserved, \n and can not be used as a function name \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ,
argv [ woptind ] ) ;
2006-01-31 03:53:10 +08:00
2005-10-06 06:37:08 +08:00
res = 1 ;
}
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( res )
{
int i ;
array_list_t names ;
int chars = 0 ;
2006-01-31 03:53:10 +08:00
2006-05-26 19:24:02 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-04 20:51:02 +08:00
const wchar_t * cfa = _ ( L " Current functions are: " ) ;
sb_append ( sb_err , cfa ) ;
chars + = wcslen ( cfa ) ;
2005-09-20 21:26:39 +08:00
al_init ( & names ) ;
function_get_names ( & names , 0 ) ;
2006-05-14 17:47:21 +08:00
sort_list ( & names ) ;
2005-09-20 21:26:39 +08:00
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
2006-05-14 17:47:21 +08:00
wchar_t * nxt = ( wchar_t * ) al_get ( & names , i ) ;
2005-09-20 21:26:39 +08:00
int l = wcslen ( nxt + 2 ) ;
2005-10-14 19:40:33 +08:00
if ( chars + l > common_get_width ( ) )
2005-09-20 21:26:39 +08:00
{
chars = 0 ;
sb_append ( sb_err , L " \n " ) ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
sb_append2 ( sb_err ,
2006-01-31 03:53:10 +08:00
nxt , L " " , ( void * ) 0 ) ;
2005-09-20 21:26:39 +08:00
}
al_destroy ( & names ) ;
2006-01-31 03:53:10 +08:00
sb_append ( sb_err , L " \n " ) ;
2005-09-20 21:26:39 +08:00
2006-02-07 02:11:01 +08:00
parser_pop_block ( ) ;
2005-09-20 21:26:39 +08:00
parser_push_block ( FAKE ) ;
}
else
{
2006-09-08 22:12:41 +08:00
function_data_t * d = halloc ( current_block , sizeof ( function_data_t ) ) ;
d - > name = halloc_wcsdup ( current_block , argv [ woptind ] ) ;
d - > description = desc ? halloc_wcsdup ( current_block , desc ) : 0 ;
d - > is_binding = is_binding ;
d - > events = events ;
d - > do_save = do_save ;
2006-02-09 23:50:20 +08:00
2005-10-06 06:37:08 +08:00
for ( i = 0 ; i < al_get_count ( events ) ; i + + )
{
event_t * e = ( event_t * ) al_get ( events , i ) ;
2006-09-08 22:12:41 +08:00
e - > function_name = d - > name ;
2005-10-06 06:37:08 +08:00
}
2006-09-08 22:12:41 +08:00
current_block - > data = d ;
2005-09-20 21:26:39 +08:00
}
2006-02-07 02:11:01 +08:00
2005-09-20 21:26:39 +08:00
current_block - > tok_pos = parser_get_pos ( ) ;
current_block - > skip = 1 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
return 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
/**
2006-02-06 05:20:50 +08:00
The random builtin . For generating random numbers .
2005-09-20 21:26:39 +08:00
*/
static int builtin_random ( wchar_t * * argv )
{
2006-01-31 03:53:10 +08:00
static int seeded = 0 ;
2006-06-15 18:35:56 +08:00
static struct drand48_data seed_buffer ;
2005-09-20 21:26:39 +08:00
int argc = builtin_count_args ( argv ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
woptind = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
const static struct woption
long_options [ ] =
{
{
2006-01-31 03:53:10 +08:00
L " help " , no_argument , 0 , ' h '
2005-09-20 21:26:39 +08:00
}
,
2006-01-31 03:53:10 +08:00
{
0 , 0 , 0 , 0
2005-09-20 21:26:39 +08:00
}
}
2006-01-31 03:53:10 +08:00
;
2005-09-20 21:26:39 +08:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int opt = wgetopt_long ( argc ,
2006-01-31 03:53:10 +08:00
argv ,
L " h " ,
long_options ,
2005-09-20 21:26:39 +08:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
case ' h ' :
2006-05-26 19:24:02 +08:00
builtin_print_help ( argv [ 0 ] , sb_out ) ;
2005-09-20 21:26:39 +08:00
break ;
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
}
2005-09-20 21:26:39 +08:00
switch ( argc - woptind )
{
case 0 :
{
2006-06-15 18:35:56 +08:00
long res ;
2005-09-20 21:26:39 +08:00
if ( ! seeded )
{
seeded = 1 ;
2006-06-15 18:35:56 +08:00
srand48_r ( time ( 0 ) , & seed_buffer ) ;
2005-09-20 21:26:39 +08:00
}
2006-06-15 18:35:56 +08:00
lrand48_r ( & seed_buffer , & res ) ;
2006-10-19 23:39:50 +08:00
sb_printf ( sb_out , L " %d \n " , abs ( res % 32767 ) ) ;
2005-09-20 21:26:39 +08:00
break ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
case 1 :
{
2006-06-15 18:35:56 +08:00
long foo ;
2005-09-20 21:26:39 +08:00
wchar_t * end = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
errno = 0 ;
foo = wcstol ( argv [ woptind ] , & end , 10 ) ;
if ( errno | | * end )
{
2005-12-15 21:59:02 +08:00
sb_printf ( sb_err ,
2006-01-31 03:53:10 +08:00
_ ( L " %ls: Seed value '%ls' is not a valid number \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ,
argv [ woptind ] ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
seeded = 1 ;
2006-06-15 18:35:56 +08:00
srand48_r ( foo , & seed_buffer ) ;
2005-09-20 21:26:39 +08:00
break ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
default :
{
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Expected zero or one argument, got %d \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ,
2005-09-20 21:26:39 +08:00
argc - woptind ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
}
2006-01-31 03:53:10 +08:00
return 0 ;
2005-09-20 21:26:39 +08:00
}
/**
The read builtin . Reads from stdin and stores the values in environment variables .
*/
static int builtin_read ( wchar_t * * argv )
{
wchar_t * buff = 0 ;
int i , argc = builtin_count_args ( argv ) ;
wchar_t * ifs ;
int place = ENV_USER ;
wchar_t * nxt ;
wchar_t * prompt = DEFAULT_READ_PROMPT ;
wchar_t * commandline = L " " ;
2006-03-11 03:51:00 +08:00
int exit_res = 0 ;
2005-09-20 21:26:39 +08:00
woptind = 0 ;
2006-05-15 06:29:05 +08:00
2005-09-20 21:26:39 +08:00
while ( 1 )
{
const static struct woption
long_options [ ] =
{
{
L " export " , no_argument , 0 , ' x '
}
,
{
L " global " , no_argument , 0 , ' g '
}
,
{
L " local " , no_argument , 0 , ' l '
}
,
2006-01-11 20:26:40 +08:00
{
L " universal " , no_argument , 0 , ' U '
}
,
2005-09-20 21:26:39 +08:00
{
L " unexport " , no_argument , 0 , ' u '
}
,
{
L " prompt " , required_argument , 0 , ' p '
}
,
{
L " command " , required_argument , 0 , ' c '
}
,
2006-05-26 19:24:02 +08:00
{
L " help " , no_argument , 0 , ' h '
}
,
2006-01-31 03:53:10 +08:00
{
0 , 0 , 0 , 0
2005-09-20 21:26:39 +08:00
}
}
2006-01-31 03:53:10 +08:00
;
2005-09-20 21:26:39 +08:00
int opt_index = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int opt = wgetopt_long ( argc ,
2006-01-31 03:53:10 +08:00
argv ,
2006-05-26 19:24:02 +08:00
L " xglUup:c:h " ,
2006-01-31 03:53:10 +08:00
long_options ,
2005-09-20 21:26:39 +08:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
case L ' x ' :
2005-09-20 21:26:39 +08:00
place | = ENV_EXPORT ;
break ;
2006-01-31 03:53:10 +08:00
case L ' g ' :
2005-09-20 21:26:39 +08:00
place | = ENV_GLOBAL ;
break ;
2006-01-31 03:53:10 +08:00
case L ' l ' :
2005-09-20 21:26:39 +08:00
place | = ENV_LOCAL ;
break ;
2006-01-31 03:53:10 +08:00
case L ' U ' :
2006-01-11 20:26:40 +08:00
place | = ENV_UNIVERSAL ;
break ;
2006-01-31 03:53:10 +08:00
case L ' u ' :
2005-09-20 21:26:39 +08:00
place | = ENV_UNEXPORT ;
break ;
case L ' p ' :
prompt = woptarg ;
break ;
case L ' c ' :
commandline = woptarg ;
break ;
2006-01-31 03:53:10 +08:00
2006-05-26 19:24:02 +08:00
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_out ) ;
return 0 ;
2005-09-20 21:26:39 +08:00
case L ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
}
2005-09-20 21:26:39 +08:00
if ( ( place & ENV_UNEXPORT ) & & ( place & ENV_EXPORT ) )
{
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_EXPUNEXP ,
argv [ 0 ] ,
parser_current_line ( ) ) ;
2006-01-31 03:53:10 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2006-01-11 20:26:40 +08:00
if ( ( place & ENV_LOCAL ? 1 : 0 ) + ( place & ENV_GLOBAL ? 1 : 0 ) + ( place & ENV_UNIVERSAL ? 1 : 0 ) > 1 )
2005-09-20 21:26:39 +08:00
{
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_GLOCAL ,
argv [ 0 ] ,
parser_current_line ( ) ) ;
2006-01-31 03:53:10 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
/*
2006-02-06 05:20:50 +08:00
Verify all variable names
2005-12-08 00:06:47 +08:00
*/
for ( i = woptind ; i < argc ; i + + )
{
wchar_t * src ;
2006-01-31 03:53:10 +08:00
2005-12-08 00:06:47 +08:00
if ( ! wcslen ( argv [ i ] ) )
{
sb_printf ( sb_err , BUILTIN_ERR_VARNAME_ZERO , argv [ 0 ] ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-12-08 00:06:47 +08:00
}
2006-01-31 03:53:10 +08:00
2005-12-08 00:06:47 +08:00
for ( src = argv [ i ] ; * src ; src + + )
{
if ( ( ! iswalnum ( * src ) ) & & ( * src ! = L ' _ ' ) )
{
sb_printf ( sb_err , BUILTIN_ERR_VARCHAR , argv [ 0 ] , * src ) ;
sb_append2 ( sb_err , parser_current_line ( ) , L " \n " , ( void * ) 0 ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-12-08 00:06:47 +08:00
}
}
2006-01-31 03:53:10 +08:00
2005-12-08 00:06:47 +08:00
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08: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 ( )
*/
if ( isatty ( 0 ) & & builtin_stdin = = 0 )
2006-01-31 03:53:10 +08:00
{
reader_push ( READ_MODE_NAME ) ;
2005-09-20 21:26:39 +08:00
reader_set_prompt ( prompt ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
reader_set_buffer ( commandline , wcslen ( commandline ) ) ;
buff = wcsdup ( reader_readline ( ) ) ;
reader_pop ( ) ;
}
else
2006-01-31 03:53:10 +08:00
{
2005-09-20 21:26:39 +08:00
string_buffer_t sb ;
2006-03-11 03:51:00 +08:00
int eof = 0 ;
2005-09-20 21:26:39 +08:00
sb_init ( & sb ) ;
2006-03-11 03:51:00 +08:00
2005-09-20 21:26:39 +08:00
while ( 1 )
{
int finished = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
wchar_t res = 0 ;
static mbstate_t state ;
memset ( & state , ' \0 ' , sizeof ( state ) ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
while ( ! finished )
{
char b ;
2006-01-31 03:53:10 +08:00
int read_res = read_blocked ( builtin_stdin , & b , 1 ) ;
2005-09-20 21:26:39 +08:00
if ( read_res < = 0 )
{
eof = 1 ;
break ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int sz = mbrtowc ( & res , & b , 1 , & state ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( sz )
{
case - 1 :
memset ( & state , ' \0 ' , sizeof ( state ) ) ;
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
case - 2 :
break ;
case 0 :
eof = 1 ;
finished = 1 ;
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
default :
finished = 1 ;
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( eof )
break ;
2006-03-11 03:51:00 +08:00
2005-09-20 21:26:39 +08:00
if ( res = = L ' \n ' )
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
sb_append_char ( & sb , res ) ;
}
2006-03-11 03:51:00 +08:00
if ( sb . used < 2 & & eof )
{
exit_res = 1 ;
}
2005-09-20 21:26:39 +08:00
buff = wcsdup ( ( wchar_t * ) sb . buff ) ;
2006-01-31 03:53:10 +08:00
sb_destroy ( & sb ) ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2006-04-19 18:08:30 +08:00
if ( i ! = argc )
2005-09-20 21:26:39 +08:00
{
2006-04-19 18:08:30 +08:00
wchar_t * state ;
2005-09-20 21:26:39 +08:00
2006-04-19 18:08:30 +08:00
ifs = env_get ( L " IFS " ) ;
if ( ifs = = 0 )
ifs = L " " ;
nxt = wcstok ( buff , ( i < argc - 1 ) ? ifs : L " " , & state ) ;
while ( i < argc )
{
env_set ( argv [ i ] , nxt ! = 0 ? nxt : L " " , place ) ;
i + + ;
if ( nxt ! = 0 )
nxt = wcstok ( 0 , ( i < argc - 1 ) ? ifs : L " " , & state ) ;
}
2005-09-20 21:26:39 +08:00
}
2006-04-19 18:08:30 +08:00
2005-09-20 21:26:39 +08:00
free ( buff ) ;
2006-04-19 18:08:30 +08:00
2006-03-11 03:51:00 +08:00
return exit_res ;
2005-09-20 21:26:39 +08:00
}
2005-10-24 23:26:25 +08:00
/**
The status builtin . Gives various status information on fish .
*/
2005-09-20 21:26:39 +08:00
static int builtin_status ( wchar_t * * argv )
{
2006-01-31 03:53:10 +08:00
enum
2005-09-20 21:26:39 +08:00
{
NORMAL ,
2006-01-31 03:53:10 +08:00
IS_SUBST ,
IS_BLOCK ,
IS_INTERACTIVE ,
IS_LOGIN ,
IS_FULL_JOB_CONTROL ,
IS_INTERACTIVE_JOB_CONTROL ,
IS_NO_JOB_CONTROL ,
2006-01-31 01:54:26 +08:00
STACK_TRACE ,
2006-01-31 03:53:10 +08:00
DONE ,
2006-02-15 03:57:47 +08:00
CURRENT_FILENAME ,
CURRENT_LINE_NUMBER
2005-09-20 21:26:39 +08:00
}
;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int mode = NORMAL ;
2006-01-31 03:53:10 +08:00
int argc = builtin_count_args ( argv ) ;
int res = 0 ;
2005-09-20 21:26:39 +08:00
woptind = 0 ;
2006-01-31 03:53:10 +08:00
const struct woption
2005-09-20 21:26:39 +08:00
long_options [ ] =
{
{
2006-01-31 03:53:10 +08:00
L " help " , no_argument , 0 , ' h '
2005-09-20 21:26:39 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " is-command-substitution " , no_argument , & mode , IS_SUBST
2005-09-20 21:26:39 +08:00
}
,
{
2006-01-31 03:53:10 +08:00
L " is-block " , no_argument , & mode , IS_BLOCK
2005-09-20 21:26:39 +08:00
}
,
2006-01-31 03:53:10 +08:00
{
L " is-interactive " , no_argument , & mode , IS_INTERACTIVE
2005-09-20 21:26:39 +08:00
}
,
2006-01-31 03:53:10 +08:00
{
L " is-login " , no_argument , & mode , IS_LOGIN
2005-09-20 21:26:39 +08:00
}
,
2006-01-31 03:53:10 +08:00
{
L " is-full-job-control " , no_argument , & mode , IS_FULL_JOB_CONTROL
2006-01-31 01:54:26 +08:00
}
,
2006-01-31 03:53:10 +08:00
{
L " is-interactive-job-control " , no_argument , & mode , IS_INTERACTIVE_JOB_CONTROL
2006-01-31 01:54:26 +08:00
}
,
2006-01-31 03:53:10 +08:00
{
L " is-no-job-control " , no_argument , & mode , IS_NO_JOB_CONTROL
2006-01-31 01:54:26 +08:00
}
,
2006-02-15 03:57:47 +08:00
{
L " current-filename " , no_argument , & mode , CURRENT_FILENAME
}
,
{
L " current-line-number " , no_argument , & mode , CURRENT_LINE_NUMBER
}
,
2006-01-31 03:53:10 +08:00
{
L " job-control " , required_argument , 0 , ' j '
2006-01-31 01:54:26 +08:00
}
,
2006-01-31 03:53:10 +08:00
{
L " print-stack-trace " , no_argument , 0 , ' t '
}
,
{
0 , 0 , 0 , 0
2005-09-20 21:26:39 +08:00
}
}
2006-01-31 03:53:10 +08:00
;
2005-09-20 21:26:39 +08:00
while ( 1 )
{
int opt_index = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int opt = wgetopt_long ( argc ,
2006-01-31 03:53:10 +08:00
argv ,
2006-09-19 22:20:42 +08:00
L " hj:t " ,
2006-01-31 03:53:10 +08:00
long_options ,
2005-09-20 21:26:39 +08:00
& opt_index ) ;
if ( opt = = - 1 )
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
case ' h ' :
2006-05-26 19:24:02 +08:00
builtin_print_help ( argv [ 0 ] , sb_out ) ;
2006-01-31 00:51:50 +08:00
return 0 ;
2005-09-20 21:26:39 +08:00
2006-01-31 03:53:10 +08: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
{
sb_printf ( sb_err ,
L " %ls: Invalid job control mode '%ls' \n " ,
woptarg ) ;
res = 1 ;
}
mode = DONE ;
2006-01-31 01:54:26 +08:00
break ;
2005-09-20 21:26:39 +08:00
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
}
if ( ! res )
{
2005-09-20 21:26:39 +08:00
2006-02-06 05:20:50 +08:00
switch ( mode )
{
2006-02-15 03:57:47 +08:00
case CURRENT_FILENAME :
{
const wchar_t * fn = parser_current_filename ( ) ;
if ( ! fn )
fn = _ ( L " Standard input " ) ;
sb_printf ( sb_out , L " %ls \n " , fn ) ;
break ;
}
case CURRENT_LINE_NUMBER :
{
sb_printf ( sb_out , L " %d \n " , parser_get_lineno ( ) ) ;
break ;
}
2006-02-06 05:20:50 +08:00
case IS_INTERACTIVE :
return ! is_interactive_session ;
2006-01-31 03:53:10 +08:00
2006-02-06 05:20:50 +08:00
case IS_SUBST :
return ! is_subshell ;
2006-01-31 03:53:10 +08:00
2006-02-06 05:20:50 +08:00
case IS_BLOCK :
return ! is_block ;
2006-01-31 03:53:10 +08:00
2006-02-06 05:20:50 +08:00
case IS_LOGIN :
return ! is_login ;
2006-01-31 03:53:10 +08:00
2006-02-06 05:20:50 +08:00
case IS_FULL_JOB_CONTROL :
return job_control_mode ! = JOB_CONTROL_ALL ;
2006-01-31 03:53:10 +08:00
2006-02-06 05:20:50 +08:00
case IS_INTERACTIVE_JOB_CONTROL :
return job_control_mode ! = JOB_CONTROL_INTERACTIVE ;
2006-01-31 03:53:10 +08:00
2006-02-06 05:20:50 +08:00
case IS_NO_JOB_CONTROL :
return job_control_mode ! = JOB_CONTROL_NONE ;
2006-01-31 01:54:26 +08:00
2006-02-06 05:20:50 +08:00
case STACK_TRACE :
{
parser_stack_trace ( current_block , sb_out ) ;
break ;
}
2006-01-31 03:53:10 +08:00
2006-02-06 05:20:50 +08:00
case NORMAL :
{
if ( is_login )
sb_printf ( sb_out , _ ( L " This is a login shell \n " ) ) ;
else
sb_printf ( sb_out , _ ( L " This is not a login shell \n " ) ) ;
2006-01-31 03:53:10 +08:00
2006-02-15 03:57:47 +08:00
sb_printf ( sb_out , _ ( L " Job control: %ls \n " ) ,
job_control_mode = = JOB_CONTROL_INTERACTIVE ? _ ( L " Only on interactive jobs " ) :
( job_control_mode = = JOB_CONTROL_NONE ? _ ( L " Never " ) : _ ( L " Always " ) ) ) ;
2006-01-31 03:53:10 +08:00
2006-02-06 05:20:50 +08:00
parser_stack_trace ( current_block , sb_out ) ;
break ;
}
2006-01-31 03:53:10 +08:00
}
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
return res ;
2005-09-20 21:26:39 +08:00
}
/**
The eval builtin . Concatenates the arguments and calls eval on the
result .
*/
static int builtin_eval ( wchar_t * * argv )
{
2005-12-14 21:46:44 +08:00
string_buffer_t sb ;
int i ;
int argc = builtin_count_args ( argv ) ;
sb_init ( & sb ) ;
2006-01-31 03:53:10 +08:00
2005-12-14 21:46:44 +08:00
for ( i = 1 ; i < argc ; i + + )
2005-09-20 21:26:39 +08:00
{
2005-12-14 21:46:44 +08:00
sb_append ( & sb , argv [ i ] ) ;
sb_append ( & sb , L " " ) ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2005-12-14 21:46:44 +08:00
eval ( ( wchar_t * ) sb . buff , block_io , TOP ) ;
sb_destroy ( & sb ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
return proc_get_last_status ( ) ;
}
/**
The exit builtin . Calls reader_exit to exit and returns the value specified .
*/
static int builtin_exit ( wchar_t * * argv )
2006-01-31 03:53:10 +08:00
{
2005-09-20 21:26:39 +08:00
int argc = builtin_count_args ( argv ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int ec = 0 ;
switch ( argc )
{
case 1 :
2006-06-09 07:57:19 +08:00
{
2006-06-13 00:51:37 +08:00
ec = proc_get_last_status ( ) ;
2005-09-20 21:26:39 +08:00
break ;
2006-06-09 07:57:19 +08:00
}
2005-09-20 21:26:39 +08:00
case 2 :
{
wchar_t * end ;
2006-01-31 03:53:10 +08:00
errno = 0 ;
2005-09-20 21:26:39 +08:00
ec = wcstol ( argv [ 1 ] , & end , 10 ) ;
if ( errno | | * end ! = 0 )
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
_ ( L " %ls: Argument '%ls' must be an integer \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ,
argv [ 1 ] ) ;
2006-01-31 03:53:10 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
break ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
default :
2006-06-09 07:57:19 +08:00
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2006-05-26 19:24:02 +08:00
BUILTIN_ERR_TOO_MANY_ARGUMENTS ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ) ;
2006-01-31 03:53:10 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-06-09 07:57:19 +08:00
}
2005-09-20 21:26:39 +08:00
}
2006-05-14 18:16:23 +08:00
reader_exit ( 1 , 0 ) ;
2005-09-20 21:26:39 +08:00
return ec ;
}
/**
Helper function for builtin_cd , used for seting the current working directory
*/
2006-06-04 06:35:33 +08:00
static int set_pwd ( wchar_t * env )
2005-09-20 21:26:39 +08:00
{
wchar_t dir_path [ 4096 ] ;
wchar_t * res = wgetcwd ( dir_path , 4096 ) ;
if ( ! res )
{
builtin_wperror ( L " wgetcwd " ) ;
return 0 ;
}
env_set ( env , dir_path , ENV_EXPORT | ENV_GLOBAL ) ;
return 1 ;
}
/**
The cd builtin . Changes the current directory to the one specified
or to $ HOME if none is specified . If ' - ' is the directory specified ,
the directory is changed to the previous working directory . The
directory can be relative to any directory in the CDPATH variable .
*/
static int builtin_cd ( wchar_t * * argv )
{
wchar_t * dir_in ;
wchar_t * dir ;
int res = 0 ;
2006-06-12 22:12:33 +08:00
void * context = halloc ( 0 , 0 ) ;
2006-06-17 21:07:08 +08:00
2006-06-12 22:12:33 +08:00
2005-09-20 21:26:39 +08:00
if ( argv [ 1 ] = = 0 )
{
dir_in = env_get ( L " HOME " ) ;
if ( ! dir_in )
{
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
_ ( L " %ls: Could not find home directory \n " ) ,
argv [ 0 ] ) ;
2006-01-31 03:53:10 +08:00
}
}
else
2005-09-20 21:26:39 +08:00
dir_in = argv [ 1 ] ;
2006-01-31 03:53:10 +08:00
2006-10-19 19:50:23 +08:00
dir = path_get_cdpath ( context , dir_in ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( ! dir )
{
2005-12-16 23:51:16 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: '%ls' is not a directory or you do not have permission to enter it \n " ) ,
2005-12-16 23:51:16 +08:00
argv [ 0 ] ,
dir_in ) ;
2006-02-04 19:36:50 +08:00
if ( ! is_interactive )
2006-06-09 07:57:19 +08:00
{
2006-02-04 19:36:50 +08:00
sb_append2 ( sb_err ,
parser_current_line ( ) ,
( void * ) 0 ) ;
2006-06-09 07:57:19 +08:00
}
2006-06-12 22:12:33 +08:00
res = 1 ;
2006-01-31 03:53:10 +08:00
}
2006-06-12 22:12:33 +08:00
else if ( wchdir ( dir ) ! = 0 )
2005-09-20 21:26:39 +08:00
{
2005-12-16 23:51:16 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: '%ls' is not a directory \n " ) ,
2005-12-16 23:51:16 +08:00
argv [ 0 ] ,
dir ) ;
2006-02-04 19:36:50 +08:00
if ( ! is_interactive )
2006-06-09 07:57:19 +08:00
{
2006-02-04 19:36:50 +08:00
sb_append2 ( sb_err ,
parser_current_line ( ) ,
( void * ) 0 ) ;
2006-06-09 07:57:19 +08:00
}
2006-02-04 19:36:50 +08:00
2006-06-12 22:12:33 +08:00
res = 1 ;
2005-09-20 21:26:39 +08:00
}
2006-06-12 22:12:33 +08:00
else if ( ! set_pwd ( L " PWD " ) )
2005-09-20 21:26:39 +08:00
{
res = 1 ;
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err , _ ( L " %ls: Could not set PWD variable \n " ) , argv [ 0 ] ) ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2006-06-12 22:12:33 +08:00
halloc_free ( context ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
return res ;
}
/**
2006-01-31 03:53:10 +08:00
The . ( dot ) builtin , sometimes called source . Evaluates the contents of a file .
2005-09-20 21:26:39 +08:00
*/
static int builtin_source ( wchar_t * * argv )
{
2005-10-19 20:07:44 +08:00
int fd ;
2005-09-20 21:26:39 +08:00
int res ;
2005-12-16 01:21:22 +08:00
struct stat buf ;
2005-12-16 23:51:16 +08:00
int argc ;
2006-01-31 03:53:10 +08:00
argc = builtin_count_args ( argv ) ;
2006-02-15 03:56:36 +08:00
if ( argc < 2 )
2005-09-20 21:26:39 +08:00
{
2006-02-15 03:56:36 +08:00
sb_printf ( sb_err , _ ( L " %ls: Expected at least one argument, got %d \n " ) , argv [ 0 ] , argc ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2005-12-16 01:21:22 +08:00
if ( wstat ( argv [ 1 ] , & buf ) = = - 1 )
{
builtin_wperror ( L " stat " ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-12-16 01:21:22 +08:00
}
2006-01-31 03:53:10 +08:00
2005-12-16 01:21:22 +08:00
if ( ! S_ISREG ( buf . st_mode ) )
{
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err , _ ( L " %ls: '%ls' is not a file \n " ) , argv [ 0 ] , argv [ 1 ] ) ;
2005-12-16 01:21:22 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-12-16 01:21:22 +08:00
}
2005-10-19 20:07:44 +08:00
if ( ( fd = wopen ( argv [ 1 ] , O_RDONLY ) ) = = - 1 )
2006-01-31 03:53:10 +08:00
{
2005-09-20 21:26:39 +08:00
builtin_wperror ( L " open " ) ;
res = 1 ;
}
else
{
2006-02-02 23:23:56 +08:00
wchar_t * fn = wrealpath ( argv [ 1 ] , 0 ) ;
const wchar_t * fn_intern ;
2006-02-15 10:22:28 +08:00
2006-02-02 23:23:56 +08:00
if ( ! fn )
{
fn_intern = intern ( argv [ 1 ] ) ;
}
else
{
fn_intern = intern ( fn ) ;
free ( fn ) ;
}
parser_push_block ( SOURCE ) ;
reader_push_current_filename ( fn_intern ) ;
2006-02-15 03:56:36 +08:00
2006-02-02 23:23:56 +08:00
current_block - > param1 . source_dest = fn_intern ;
2006-01-28 19:34:40 +08:00
2006-02-15 03:56:36 +08:00
parse_util_set_argv ( argv + 2 ) ;
2006-03-10 21:38:09 +08:00
2006-01-31 03:53:10 +08:00
res = reader_read ( fd ) ;
2006-02-15 10:22:28 +08:00
2006-01-28 19:34:40 +08:00
parser_pop_block ( ) ;
2005-09-20 21:26:39 +08:00
if ( res )
{
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Error while reading file '%ls' \n " ) ,
2005-09-20 21:26:39 +08:00
argv [ 0 ] ,
2006-03-10 21:38:09 +08:00
argv [ 1 ] ) ;
2005-09-20 21:26:39 +08:00
}
2005-10-19 20:07:44 +08:00
/*
Do not close fd after calling reader_read . reader_read
automatically closes it before calling eval .
*/
2005-09-20 21:26:39 +08:00
2005-10-19 20:07:44 +08:00
reader_pop_current_filename ( ) ;
2005-09-20 21:26:39 +08: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 17:33:10 +08:00
jobs were used .
2005-09-20 21:26:39 +08:00
*/
static void make_first ( job_t * j )
{
job_t * prev = 0 ;
job_t * curr ;
for ( curr = first_job ; curr ! = j ; curr = curr - > next )
{
prev = curr ;
}
if ( curr = = j )
{
if ( prev = = 0 )
2006-06-09 07:57:19 +08:00
{
2005-09-20 21:26:39 +08:00
return ;
2006-06-09 07:57:19 +08:00
}
2005-09-20 21:26:39 +08:00
else
{
prev - > next = curr - > next ;
curr - > next = first_job ;
first_job = curr ;
}
}
}
/**
Builtin for putting a job in the foreground
*/
static int builtin_fg ( wchar_t * * argv )
{
2006-04-24 23:34:34 +08:00
job_t * j = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( argv [ 1 ] = = 0 )
{
/*
2006-06-04 06:35:33 +08:00
Select last constructed job ( I . e . first job in the job que )
that is possible to put in the foreground
2005-09-20 21:26:39 +08:00
*/
2006-01-19 21:15:15 +08:00
for ( j = first_job ; j ; j = j - > next )
{
2006-06-04 06:35:33 +08:00
if ( j - > constructed & & ( ! job_is_completed ( j ) ) & &
( ( job_is_stopped ( j ) | | ! j - > fg ) & & ( j - > job_control ) ) )
2006-06-09 07:57:19 +08:00
{
2006-01-19 21:15:15 +08:00
break ;
2006-06-09 07:57:19 +08:00
}
2006-01-31 03:53:10 +08:00
}
2006-01-19 00:47:50 +08:00
if ( ! j )
{
sb_printf ( sb_err ,
2006-01-19 21:15:15 +08:00
_ ( L " %ls: There are no suitable jobs \n " ) ,
2006-01-19 00:47:50 +08:00
argv [ 0 ] ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
}
2005-09-20 21:26:39 +08: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-05 05:42:04 +08:00
wchar_t * endptr ;
int pid ;
int found_job = 0 ;
errno = 0 ;
pid = wcstol ( argv [ 1 ] , & endptr , 10 ) ;
if ( ! ( * endptr | | errno ) )
{
j = job_get_from_pid ( pid ) ;
if ( j )
found_job = 1 ;
}
if ( found_job )
2005-09-20 21:26:39 +08:00
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2006-02-06 05:20:50 +08:00
_ ( L " %ls: Ambiguous job \n " ) ,
2006-01-31 03:53:10 +08:00
argv [ 0 ] ) ;
2005-09-20 21:26:39 +08:00
}
else
{
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
2006-01-31 03:53:10 +08:00
_ ( L " %ls: '%ls' is not a job \n " ) ,
argv [ 0 ] ,
2006-01-04 20:51:02 +08:00
argv [ 1 ] ) ;
2005-09-20 21:26:39 +08:00
}
2006-10-05 05:42:04 +08:00
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-31 03:53:10 +08:00
2006-01-19 21:15:15 +08:00
j = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
else
{
2006-04-24 23:34:34 +08:00
wchar_t * end ;
2006-10-05 05:42:04 +08:00
int pid ;
errno = 0 ;
pid = abs ( wcstol ( argv [ 1 ] , & end , 10 ) ) ;
2006-04-24 23:34:34 +08:00
2006-10-05 05:42:04 +08:00
if ( * end | | errno )
2006-01-19 21:15:15 +08:00
{
2006-04-24 23:34:34 +08:00
sb_printf ( sb_err ,
2006-10-05 05:39:48 +08:00
BUILTIN_ERR_NOT_NUMBER ,
2006-04-24 23:34:34 +08:00
argv [ 0 ] ,
argv [ 1 ] ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-19 21:15:15 +08:00
}
2006-04-24 23:34:34 +08:00
else
2006-01-31 01:54:26 +08:00
{
2006-04-24 23:34:34 +08:00
j = job_get_from_pid ( pid ) ;
if ( ! j | | ! j - > constructed | | job_is_completed ( j ) )
{
sb_printf ( sb_err ,
_ ( L " %ls: No suitable job: %d \n " ) ,
argv [ 0 ] ,
pid ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
j = 0 ;
}
else if ( ! j - > job_control )
{
sb_printf ( sb_err ,
_ ( L " %ls: Can't put job %d, '%ls' to foreground because it is not under job control \n " ) ,
argv [ 0 ] ,
pid ,
j - > command ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
j = 0 ;
}
2006-01-31 01:54:26 +08:00
}
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2006-01-19 21:15:15 +08:00
if ( j )
2005-09-20 21:26:39 +08:00
{
if ( builtin_err_redirect )
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2005-12-15 21:59:02 +08:00
FG_MSG ,
2006-01-31 03:53:10 +08:00
j - > job_id ,
2005-09-20 21:26:39 +08:00
j - > command ) ;
}
else
{
2005-12-15 21:59:02 +08: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 21:26:39 +08:00
fwprintf ( stderr ,
2005-12-15 21:59:02 +08:00
FG_MSG ,
2006-01-31 03:53:10 +08:00
j - > job_id ,
2005-09-20 21:26:39 +08:00
j - > command ) ;
}
2005-12-15 21:59:02 +08:00
2006-01-19 21:15:15 +08:00
wchar_t * ft = tok_first ( j - > command ) ;
if ( ft ! = 0 )
env_set ( L " _ " , ft , ENV_EXPORT ) ;
free ( ft ) ;
reader_write_title ( ) ;
2006-01-31 03:53:10 +08:00
2006-01-19 21:15:15 +08:00
make_first ( j ) ;
j - > fg = 1 ;
2006-01-31 03:53:10 +08:00
2006-01-19 21:15:15 +08:00
job_continue ( j , job_is_stopped ( j ) ) ;
}
return j ! = 0 ;
2005-09-20 21:26:39 +08:00
}
/**
Helper function for builtin_bg ( )
*/
2006-01-19 21:15:15 +08:00
static int send_to_bg ( job_t * j , const wchar_t * name )
2005-09-20 21:26:39 +08:00
{
if ( j = = 0 )
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Unknown job '%ls' \n " ) ,
L " bg " ,
name ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( L " bg " , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 03:53:10 +08:00
}
2006-01-31 01:54:26 +08:00
else if ( ! j - > job_control )
{
sb_printf ( sb_err ,
_ ( L " %ls: Can't put job %d, '%ls' to background because it is not under job control \n " ) ,
L " bg " ,
j - > job_id ,
j - > command ) ;
builtin_print_help ( L " bg " , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2006-01-31 01:54:26 +08:00
}
2005-09-20 21:26:39 +08:00
else
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " Send job %d '%ls' to background \n " ) ,
2005-09-20 21:26:39 +08:00
j - > job_id ,
j - > command ) ;
}
make_first ( j ) ;
j - > fg = 0 ;
job_continue ( j , job_is_stopped ( j ) ) ;
2006-01-19 21:15:15 +08:00
return 0 ;
2005-09-20 21:26:39 +08:00
}
/**
Builtin for putting a job in the background
*/
static int builtin_bg ( wchar_t * * argv )
{
2006-01-19 21:15:15 +08:00
int res = 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( argv [ 1 ] = = 0 )
{
job_t * j ;
2006-01-19 21:15:15 +08:00
for ( j = first_job ; j ; j = j - > next )
{
2006-01-31 01:54:26 +08:00
if ( job_is_stopped ( j ) & & j - > job_control & & ( ! job_is_completed ( j ) ) )
2006-06-09 07:57:19 +08:00
{
2006-01-19 21:15:15 +08:00
break ;
2006-06-09 07:57:19 +08:00
}
2006-01-19 21:15:15 +08:00
}
2006-06-09 07:57:19 +08:00
2006-01-19 21:15:15 +08:00
if ( ! j )
{
sb_printf ( sb_err ,
_ ( L " %ls: There are no suitable jobs \n " ) ,
argv [ 0 ] ) ;
res = 1 ;
}
else
{
res = send_to_bg ( j , _ ( L " (default) " ) ) ;
}
2005-09-20 21:26:39 +08:00
}
2006-01-19 21:15:15 +08:00
else
2005-09-20 21:26:39 +08:00
{
2006-01-19 21:15:15 +08:00
for ( argv + + ; ! res & & * argv ! = 0 ; argv + + )
{
int pid = wcstol ( * argv , 0 , 10 ) ;
res | = send_to_bg ( job_get_from_pid ( pid ) , * argv ) ;
}
2005-09-20 21:26:39 +08:00
}
2006-01-19 21:15:15 +08:00
return res ;
2005-09-20 21:26:39 +08:00
}
/**
Builtin for looping over a list
*/
static int builtin_for ( wchar_t * * argv )
{
int argc = builtin_count_args ( argv ) ;
int res = 1 ;
2006-01-31 03:53:10 +08:00
if ( argc < 3 )
2005-09-20 21:26:39 +08:00
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2006-09-26 20:41:09 +08:00
BUILTIN_FOR_ERR_COUNT ,
2006-09-19 22:21:40 +08:00
argv [ 0 ] ,
argc ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
}
2006-04-21 22:29:39 +08:00
else if ( wcsvarname ( argv [ 1 ] ) )
2005-09-20 21:26:39 +08:00
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2006-10-01 23:57:34 +08:00
BUILTIN_FOR_ERR_NAME ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ,
argv [ 1 ] ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
}
else if ( wcscmp ( argv [ 2 ] , L " in " ) ! = 0 )
{
2005-12-15 21:59:02 +08:00
sb_printf ( sb_err ,
2006-05-22 06:16:04 +08:00
BUILTIN_FOR_ERR_IN ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
}
else
{
res = 0 ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( res )
{
parser_push_block ( FAKE ) ;
}
else
{
parser_push_block ( FOR ) ;
2005-10-12 03:31:16 +08:00
al_init ( & current_block - > param2 . for_vars ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
int i ;
current_block - > tok_pos = parser_get_pos ( ) ;
2006-02-11 08:13:17 +08:00
current_block - > param1 . for_variable = halloc_wcsdup ( current_block , argv [ 1 ] ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
for ( i = argc - 1 ; i > 3 ; i - - )
{
2006-02-11 08:13:17 +08:00
al_push ( & current_block - > param2 . for_vars , halloc_wcsdup ( current_block , argv [ i ] ) ) ;
2005-09-20 21:26:39 +08:00
}
2006-02-07 02:11:01 +08:00
halloc_register ( current_block , current_block - > param2 . for_vars . arr ) ;
2005-09-20 21:26:39 +08:00
if ( argc > 3 )
{
2005-10-12 03:31:16 +08:00
env_set ( current_block - > param1 . for_variable , argv [ 3 ] , ENV_LOCAL ) ;
2005-09-20 21:26:39 +08:00
}
else
{
current_block - > skip = 1 ;
2006-01-31 03:53:10 +08:00
}
2005-09-20 21:26:39 +08:00
}
return res ;
}
2005-10-24 23:26:25 +08:00
/**
The begin builtin . Creates a nex block .
*/
2005-09-20 21:26:39 +08:00
static int builtin_begin ( wchar_t * * argv )
{
parser_push_block ( BEGIN ) ;
current_block - > tok_pos = parser_get_pos ( ) ;
2006-07-13 01:31:41 +08:00
return proc_get_last_status ( ) ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2006-10-01 23:57:34 +08:00
/**
Define the function specified by the function_data_t structure . If
the do_save flag is set , also write it out to file .
*/
2006-09-08 22:12:41 +08:00
static void builtin_end_add_function_def ( function_data_t * d )
{
/**
Copy the text from the beginning of the function
2006-10-01 23:57:34 +08:00
until the end command and use as the new definition
for the specified function
2006-09-08 22:12:41 +08:00
*/
void * context = halloc ( 0 , 0 ) ;
wchar_t * def = halloc_wcsndup ( context ,
parser_get_buffer ( ) + current_block - > tok_pos ,
parser_get_job_pos ( ) - current_block - > tok_pos ) ;
function_add ( d - > name ,
def ,
d - > description ,
d - > events ,
d - > is_binding ) ;
if ( d - > do_save )
{
wchar_t * func_path ;
array_list_t func_path_list ;
func_path = env_get ( L " fish_function_path " ) ;
if ( ! func_path )
{
sb_printf ( sb_err ,
_ ( L " %ls: Can't save the function '%ls' because the function path is undefined. Define the variable $fish_function_path to a suitable directory and retry " ) ,
L " function " ,
d - > name ) ;
}
else
{
wchar_t * target_dir = 0 ;
int i ;
struct stat buf ;
al_init ( & func_path_list ) ;
tokenize_variable_array ( func_path , & func_path_list ) ;
for ( i = 0 ; i < al_get_count ( & func_path_list ) ; i + + )
{
wchar_t * dir = ( wchar_t * ) al_get ( & func_path_list , i ) ;
if ( ! wstat ( dir , & buf ) )
{
if ( S_ISDIR ( buf . st_mode ) & &
( waccess ( dir , W_OK ) = = 0 ) )
{
/*
We have found the first writeable directory
in the path
*/
target_dir = dir ;
break ;
}
}
else
{
if ( errno = = ENOENT )
{
wchar_t * dir_copy = halloc_wcsdup ( context , dir ) ;
array_list_t * subdirs = al_halloc ( context ) ;
//debug( 0, L"Directory %ls doesn't exist. Check if parent is writeable by us", dir );
while ( 1 )
{
wchar_t * sub = halloc_wcsdup ( context , dir_copy ) ;
al_push ( subdirs , sub ) ;
dir_copy = wdirname ( dir_copy ) ;
if ( ! wstat ( dir_copy , & buf ) )
{
if ( S_ISDIR ( buf . st_mode ) & &
( waccess ( dir_copy , W_OK ) = = 0 ) )
{
int j ;
int create_err = 0 ;
for ( j = al_get_count ( subdirs ) - 1 ; j > = 0 ; j - - )
{
wchar_t * cre = ( wchar_t * ) al_get ( subdirs , j ) ;
if ( wmkdir ( cre , 0700 ) )
{
create_err = 1 ;
break ;
}
}
if ( ! create_err )
target_dir = dir ;
break ;
}
else
{
break ;
}
}
else
{
if ( errno ! = ENOENT )
{
break ;
}
}
if ( wcslen ( dir_copy ) < = 1 )
break ;
}
if ( target_dir )
break ;
}
}
}
//debug( 0, L"target directory is %ls", target_dir );
if ( target_dir )
{
int err = 0 ;
string_buffer_t filename ;
FILE * out ;
wchar_t * efunc = L " unknown " ;
sb_init ( & filename ) ;
sb_printf ( & filename ,
L " %ls/%ls.fish " ,
target_dir ,
d - > name ) ;
if ( ( out = wfopen ( ( wchar_t * ) filename . buff , " w " ) ) )
{
string_buffer_t * tmp = sb_halloc ( context ) ;
functions_def ( d - > name , tmp ) ;
fwprintf ( out , L " %ls " , ( wchar_t * ) tmp - > buff ) ;
if ( fclose ( out ) )
{
efunc = L " fclose " ;
err = 1 ;
}
}
else
{
efunc = L " wfopen " ;
err = 1 ;
}
sb_destroy ( & filename ) ;
if ( err )
{
sb_printf ( sb_err ,
_ ( L " %ls: Unexpected error while saving function %ls \n " ) ,
L " function " ,
d - > name ) ;
builtin_wperror ( efunc ) ;
}
}
al_foreach ( & func_path_list , & free ) ;
al_destroy ( & func_path_list ) ;
}
}
halloc_free ( context ) ;
}
2005-09-20 21:26:39 +08:00
/**
Builtin for ending a block of code , such as a for - loop or an if statement .
2006-01-31 03:53:10 +08:00
The end command is whare a lot of the block - level magic happens .
2005-09-20 21:26:39 +08:00
*/
static int builtin_end ( wchar_t * * argv )
{
2006-01-05 23:37:53 +08:00
if ( ! current_block - > outer )
2005-09-20 21:26:39 +08:00
{
2005-12-15 21:59:02 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Not inside of block \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08: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-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( current_block - > type )
{
case WHILE :
{
/*
If this is a while loop , we rewind the loop unless
it ' s the last lap , in which case we continue .
*/
if ( ! ( current_block - > skip & & ( current_block - > loop_status ! = LOOP_CONTINUE ) ) )
{
current_block - > loop_status = LOOP_NORMAL ;
current_block - > skip = 0 ;
kill_block = 0 ;
parser_set_pos ( current_block - > tok_pos ) ;
2005-10-12 03:31:16 +08:00
current_block - > param1 . while_state = WHILE_TEST_AGAIN ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
break ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
case IF :
case SUBST :
case BEGIN :
/*
2006-06-04 06:35:33 +08:00
Nothing special happens at the end of these commands . The scope just ends .
2005-09-20 21:26:39 +08:00
*/
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
break ;
case FOR :
{
/*
set loop variable to next element , and rewind to the beginning of the block .
*/
if ( current_block - > loop_status = = LOOP_BREAK )
{
2006-02-07 02:11:01 +08:00
al_truncate ( & current_block - > param2 . for_vars , 0 ) ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2005-10-12 03:31:16 +08:00
if ( al_get_count ( & current_block - > param2 . for_vars ) )
2005-09-20 21:26:39 +08:00
{
2005-10-12 03:31:16 +08:00
wchar_t * val = ( wchar_t * ) al_pop ( & current_block - > param2 . for_vars ) ;
env_set ( current_block - > param1 . for_variable , val , ENV_LOCAL ) ;
2005-09-20 21:26:39 +08:00
current_block - > loop_status = LOOP_NORMAL ;
current_block - > skip = 0 ;
2006-02-07 02:11:01 +08:00
2005-09-20 21:26:39 +08:00
kill_block = 0 ;
parser_set_pos ( current_block - > tok_pos ) ;
}
break ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
case FUNCTION_DEF :
{
2006-06-04 06:35:33 +08:00
2006-09-08 22:12:41 +08:00
function_data_t * d = ( function_data_t * ) current_block - > data ;
if ( d )
{
builtin_end_add_function_def ( d ) ;
}
else
{
debug ( 0 ,
_ ( L " %ls: Missing function definition information. This is a fish bug. If you can reproduce it, please file a bug report to %s. " ) ,
argv [ 0 ] ,
PACKAGE_BUGREPORT ) ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
break ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
if ( kill_block )
{
parser_pop_block ( ) ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
/*
If everything goes ok , return status of last command to execute .
*/
return proc_get_last_status ( ) ;
2006-01-31 03:53:10 +08:00
}
2005-09-20 21:26:39 +08:00
}
/**
Builtin for executing commands if an if statement is false
*/
static int builtin_else ( wchar_t * * argv )
{
2006-01-31 03:53:10 +08:00
if ( current_block = = 0 | |
2005-09-20 21:26:39 +08:00
current_block - > type ! = IF | |
2005-10-12 03:31:16 +08:00
current_block - > param1 . if_state ! = 1 )
2005-09-20 21:26:39 +08:00
{
2005-12-15 21:59:02 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Not inside of 'if' block \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
else
{
2005-10-12 03:31:16 +08:00
current_block - > param1 . if_state + + ;
2005-09-20 21:26:39 +08:00
current_block - > skip = ! current_block - > skip ;
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 .
*/
static int builtin_break_continue ( wchar_t * * argv )
{
int is_break = ( wcscmp ( argv [ 0 ] , L " break " ) = = 0 ) ;
int argc = builtin_count_args ( argv ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
block_t * b = current_block ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( argc ! = 1 )
{
2006-01-04 20:51:02 +08:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
2005-12-15 21:59:02 +08:00
argv [ 1 ] ) ;
2006-01-04 20:51:02 +08:00
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
while ( ( b ! = 0 ) & &
( b - > type ! = WHILE ) & &
2005-09-20 21:26:39 +08:00
( b - > type ! = FOR ) )
{
b = b - > outer ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( b = = 0 )
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
_ ( L " %ls: Not inside of loop \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
b = current_block ;
2006-01-31 03:53:10 +08:00
while ( ( b - > type ! = WHILE ) & &
2005-09-20 21:26:39 +08:00
( b - > type ! = FOR ) )
{
b - > skip = 1 ;
b = b - > outer ;
}
b - > skip = 1 ;
b - > loop_status = is_break ? LOOP_BREAK : LOOP_CONTINUE ;
return 0 ;
}
/**
Function for handling the \ c return builtin
*/
static int builtin_return ( wchar_t * * argv )
{
int argc = builtin_count_args ( argv ) ;
2006-06-13 00:48:54 +08:00
int status = proc_get_last_status ( ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
block_t * b = current_block ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
switch ( argc )
{
case 1 :
break ;
case 2 :
{
wchar_t * end ;
2006-01-31 03:53:10 +08:00
errno = 0 ;
2005-09-20 21:26:39 +08:00
status = wcstol ( argv [ 1 ] , & end , 10 ) ;
if ( errno | | * end ! = 0 )
{
2005-12-15 21:59:02 +08:00
sb_printf ( sb_err ,
2006-01-31 03:53:10 +08:00
_ ( L " %ls: Argument '%ls' must be an integer \n " ) ,
argv [ 0 ] ,
2005-12-15 21:59:02 +08:00
argv [ 1 ] ) ;
2006-01-31 03:53:10 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
break ;
2005-09-20 21:26:39 +08:00
}
default :
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
_ ( L " %ls: Too many arguments \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
while ( ( b ! = 0 ) & &
2005-09-20 21:26:39 +08:00
( b - > type ! = FUNCTION_CALL ) )
{
b = b - > outer ;
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( b = = 0 )
{
2005-12-15 21:59:02 +08:00
sb_printf ( sb_err ,
2006-01-31 03:53:10 +08:00
_ ( L " %ls: Not inside of function \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ) ;
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
b = current_block ;
while ( ( b - > type ! = FUNCTION_CALL ) )
{
2006-09-01 04:53:20 +08:00
b - > type = FAKE ;
2005-09-20 21:26:39 +08:00
b - > skip = 1 ;
b = b - > outer ;
}
b - > skip = 1 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
return status ;
}
/**
2006-10-01 23:57:34 +08:00
Builtin for executing one of several blocks of commands depending
on the value of an argument .
2005-09-20 21:26:39 +08:00
*/
static int builtin_switch ( wchar_t * * argv )
{
2006-01-31 03:53:10 +08:00
int res = 0 ;
2005-09-20 21:26:39 +08:00
int argc = builtin_count_args ( argv ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( argc ! = 2 )
{
2006-01-31 03:53:10 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: Expected exactly one argument, got %d \n " ) ,
2005-09-20 21:26:39 +08:00
argv [ 0 ] ,
argc - 1 ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
res = 1 ;
parser_push_block ( FAKE ) ;
}
else
{
parser_push_block ( SWITCH ) ;
2006-02-11 08:13:17 +08:00
current_block - > param1 . switch_value = halloc_wcsdup ( current_block , argv [ 1 ] ) ;
2005-09-20 21:26:39 +08:00
current_block - > skip = 1 ;
2005-10-12 03:31:16 +08:00
current_block - > param2 . switch_taken = 0 ;
2005-09-20 21:26:39 +08:00
}
2006-08-28 20:02:44 +08:00
2005-09-20 21:26:39 +08:00
return res ;
}
/**
2006-10-01 23:57:34 +08:00
Builtin used together with the switch builtin for conditional
execution
2005-09-20 21:26:39 +08:00
*/
static int builtin_case ( wchar_t * * argv )
{
int argc = builtin_count_args ( argv ) ;
int i ;
wchar_t * unescaped = 0 ;
2006-08-28 20:02:44 +08:00
2005-09-20 21:26:39 +08:00
if ( current_block - > type ! = SWITCH )
{
2005-12-15 21:59:02 +08:00
sb_printf ( sb_err ,
2006-01-04 20:51:02 +08:00
_ ( L " %ls: 'case' command while not in switch block \n " ) ,
2005-12-15 21:59:02 +08:00
argv [ 0 ] ) ;
2006-01-11 22:17:35 +08:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-10-09 09:21:02 +08:00
return STATUS_BUILTIN_ERROR ;
2005-09-20 21:26:39 +08:00
}
2006-08-28 20:02:44 +08:00
2005-09-20 21:26:39 +08:00
current_block - > skip = 1 ;
2006-08-28 20:02:44 +08:00
2005-10-12 03:31:16 +08:00
if ( current_block - > param2 . switch_taken )
2005-09-20 21:26:39 +08:00
{
return 0 ;
}
2006-08-28 20:02:44 +08:00
2005-09-20 21:26:39 +08:00
for ( i = 1 ; i < argc ; i + + )
{
2006-08-28 20:02:44 +08:00
int match ;
2006-02-19 09:14:32 +08:00
2006-08-28 20:02:44 +08:00
unescaped = parse_util_unescape_wildcards ( argv [ i ] ) ;
match = wildcard_match ( current_block - > param1 . switch_value , unescaped ) ;
free ( unescaped ) ;
2006-02-19 09:14:32 +08:00
2006-08-28 20:02:44 +08:00
if ( match )
2005-09-20 21:26:39 +08:00
{
current_block - > skip = 0 ;
2005-10-12 03:31:16 +08:00
current_block - > param2 . switch_taken = 1 ;
2006-01-31 03:53:10 +08:00
break ;
2005-09-20 21:26:39 +08:00
}
}
2006-08-28 20:02:44 +08:00
2006-01-31 03:53:10 +08:00
return 0 ;
2005-09-20 21:26:39 +08:00
}
/*
END OF BUILTIN COMMANDS
Below are functions for handling the builtin commands
*/
2005-12-15 21:59:02 +08:00
2006-06-17 21:07:08 +08:00
/**
Data about all the builtin commands in fish
*/
2006-02-06 05:20:50 +08:00
const static builtin_data_t builtin_data [ ] =
2005-09-20 21:26:39 +08:00
{
2006-02-06 05:20:50 +08:00
{
L " exit " , & builtin_exit , N_ ( L " Exit the shell " )
}
,
{
L " block " , & builtin_block , N_ ( L " Temporarily block delivery of events " )
}
,
{
L " builtin " , & builtin_builtin , N_ ( L " Run a builtin command instead of a function " )
}
,
{
L " cd " , & builtin_cd , N_ ( L " Change working directory " )
}
,
{
L " function " , & builtin_function , N_ ( L " Define a new function " )
}
,
{
L " functions " , & builtin_functions , N_ ( L " List or remove functions " )
}
,
{
L " complete " , & builtin_complete , N_ ( L " Edit command specific completions " )
}
,
{
L " end " , & builtin_end , N_ ( L " End a block of commands " )
}
,
{
L " else " , & builtin_else , N_ ( L " Evaluate block if condition is false " )
}
,
{
L " eval " , & builtin_eval , N_ ( L " Evaluate parameters as a command " )
}
,
{
L " for " , & builtin_for , N_ ( L " Perform a set of commands multiple times " )
}
,
{
L " . " , & builtin_source , N_ ( L " Evaluate contents of file " )
}
,
{
L " set " , & builtin_set , N_ ( L " Handle environment variables " )
}
,
{
L " fg " , & builtin_fg , N_ ( L " Send job to foreground " )
}
,
{
L " bg " , & builtin_bg , N_ ( L " Send job to background " )
}
,
{
L " jobs " , & builtin_jobs , N_ ( L " Print currently running jobs " )
}
,
{
L " read " , & builtin_read , N_ ( L " Read a line of input into variables " )
}
,
{
L " break " , & builtin_break_continue , N_ ( L " Stop the innermost loop " )
}
,
{
L " continue " , & builtin_break_continue , N_ ( L " Skip the rest of the current lap of the innermost loop " )
}
,
{
L " return " , & builtin_return , N_ ( L " Stop the currently evaluated function " )
}
,
{
L " commandline " , & builtin_commandline , N_ ( L " Set or get the commandline " )
}
,
{
L " switch " , & builtin_switch , N_ ( L " Conditionally execute a block of commands " )
}
,
{
L " case " , & builtin_case , N_ ( L " Conditionally execute a block of commands " )
}
,
{
L " bind " , & builtin_bind , N_ ( L " Handle fish key bindings " )
}
,
{
L " random " , & builtin_random , N_ ( L " Generate random number " )
}
,
{
L " status " , & builtin_status , N_ ( L " Return status information about fish " )
}
,
{
L " ulimit " , & builtin_ulimit , N_ ( L " Set or get the shells resource usage limits " )
}
,
2006-06-04 06:35:33 +08:00
{
L " begin " , & builtin_begin , N_ ( L " Create a block of code " )
}
,
2006-01-31 03:53:10 +08:00
/*
2006-02-06 05:20:50 +08:00
Builtins that are handled directly by the parser . They are
bound to a noop function only so that they show up in the
listings of builtin commands , etc . .
2005-09-20 21:26:39 +08:00
*/
2006-02-06 05:20:50 +08:00
{
L " command " , & builtin_generic , N_ ( L " Run a program instead of a function or builtin " )
}
,
{
L " if " , & builtin_generic , N_ ( L " Evaluate block if condition is true " )
}
,
{
L " while " , & builtin_generic , N_ ( L " Perform a command multiple times " )
}
,
{
L " not " , & builtin_generic , N_ ( L " Negate exit status of job " )
}
,
{
L " and " , & builtin_generic , N_ ( L " Execute command if previous command suceeded " )
}
,
{
L " or " , & builtin_generic , N_ ( L " Execute command if previous command failed " )
}
,
{
L " exec " , & builtin_generic , N_ ( L " Run command in current process " )
}
,
2005-09-20 21:26:39 +08:00
/*
This is not a builtin , but fish handles it ' s help display
2006-02-06 05:20:50 +08:00
internally . So some ugly special casing to make sure ' count - h '
displays the help for count , but ' count ( echo - h ) ' does not .
2005-09-20 21:26:39 +08:00
*/
2006-02-06 05:20:50 +08:00
{
L " count " , & builtin_generic , 0
}
,
{
0 , 0 , 0
}
2006-02-05 21:08:40 +08:00
}
;
2006-01-31 03:53:10 +08:00
2006-02-05 21:08:40 +08:00
void builtin_init ( )
{
int i ;
al_init ( & io_stack ) ;
hash_init ( & builtin , & hash_wcs_func , & hash_wcs_cmp ) ;
2006-02-06 05:20:50 +08:00
for ( i = 0 ; builtin_data [ i ] . name ; i + + )
2006-02-05 21:08:40 +08:00
{
2006-02-06 05:20:50 +08:00
hash_put ( & builtin , builtin_data [ i ] . name , builtin_data [ i ] . func ) ;
intern_static ( builtin_data [ i ] . name ) ;
2006-02-05 21:08:40 +08:00
}
2005-09-20 21:26:39 +08:00
}
void builtin_destroy ( )
{
if ( desc )
{
2006-01-31 03:53:10 +08:00
hash_destroy ( desc ) ;
2005-09-20 21:26:39 +08:00
free ( desc ) ;
2006-02-15 10:49:00 +08:00
desc = 0 ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
al_destroy ( & io_stack ) ;
hash_destroy ( & builtin ) ;
}
int builtin_exists ( wchar_t * cmd )
{
2006-06-21 08:48:36 +08:00
CHECK ( cmd , 0 ) ;
2005-09-20 21:26:39 +08:00
/*
Count is not a builtin , but it ' s help is handled internally by
fish , so it is in the hash_table_t .
*/
if ( wcscmp ( cmd , L " count " ) = = 0 )
return 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
return ( hash_get ( & builtin , cmd ) ! = 0 ) ;
}
/**
Return true if the specified builtin should handle it ' s own help ,
false otherwise .
*/
static int internal_help ( wchar_t * cmd )
{
if ( wcscmp ( cmd , L " for " ) = = 0 | |
wcscmp ( cmd , L " while " ) = = 0 | |
wcscmp ( cmd , L " function " ) = = 0 | |
wcscmp ( cmd , L " if " ) = = 0 | |
wcscmp ( cmd , L " end " ) = = 0 | |
2006-01-31 03:53:10 +08:00
wcscmp ( cmd , L " switch " ) = = 0 )
2005-09-20 21:26:39 +08:00
return 1 ;
return 0 ;
}
int builtin_run ( wchar_t * * argv )
{
int ( * cmd ) ( wchar_t * * argv ) = 0 ;
2006-06-09 07:52:12 +08:00
2006-06-21 08:48:36 +08:00
CHECK ( argv , 1 ) ;
CHECK ( argv [ 0 ] , 1 ) ;
2006-03-29 08:14:50 +08:00
cmd = ( int ( * ) ( wchar_t * * ) ) hash_get ( & builtin , argv [ 0 ] ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( argv [ 1 ] ! = 0 & & ! internal_help ( argv [ 0 ] ) )
{
if ( argv [ 2 ] = = 0 & & ( parser_is_help ( argv [ 1 ] , 0 ) ) )
{
builtin_print_help ( argv [ 0 ] , sb_out ) ;
return 0 ;
}
}
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( cmd ! = 0 )
{
int status ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
status = cmd ( argv ) ;
return status ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
}
else
{
2006-01-04 20:51:02 +08:00
debug ( 0 , _ ( L " Unknown builtin '%ls' " ) , argv [ 0 ] ) ;
2005-09-20 21:26:39 +08:00
}
2006-01-31 03:53:10 +08:00
return 1 ;
2005-09-20 21:26:39 +08:00
}
void builtin_get_names ( array_list_t * list )
{
2006-06-21 08:48:36 +08:00
CHECK ( list , ) ;
2005-09-20 21:26:39 +08:00
hash_get_keys ( & builtin , list ) ;
}
const wchar_t * builtin_get_desc ( const wchar_t * b )
{
2006-06-21 08:48:36 +08:00
CHECK ( b , 0 ) ;
2006-06-09 07:52:12 +08:00
2005-09-20 21:26:39 +08:00
if ( ! desc )
{
2006-02-05 21:08:40 +08:00
int i ;
2005-09-20 21:26:39 +08:00
desc = malloc ( sizeof ( hash_table_t ) ) ;
2006-01-31 03:53:10 +08:00
if ( ! desc )
2005-09-20 21:26:39 +08:00
return 0 ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
hash_init ( desc , & hash_wcs_func , & hash_wcs_cmp ) ;
2006-02-06 05:20:50 +08:00
for ( i = 0 ; builtin_data [ i ] . name ; i + + )
2006-02-05 21:08:40 +08:00
{
2006-02-06 05:20:50 +08:00
hash_put ( desc , builtin_data [ i ] . name , builtin_data [ i ] . desc ) ;
2006-02-05 21:08:40 +08:00
}
2006-01-08 10:56:56 +08:00
}
2006-01-31 03:53:10 +08:00
return _ ( hash_get ( desc , b ) ) ;
2005-09-20 21:26:39 +08:00
}
2006-06-04 06:35:33 +08:00
void builtin_push_io ( int in )
2005-09-20 21:26:39 +08:00
{
if ( builtin_stdin ! = - 1 )
{
2006-08-01 00:23:39 +08:00
al_push_long ( & io_stack , ( long ) builtin_stdin ) ;
2005-09-20 21:26:39 +08:00
al_push ( & io_stack , sb_out ) ;
2006-01-31 03:53:10 +08:00
al_push ( & io_stack , sb_err ) ;
2005-09-20 21:26:39 +08:00
}
builtin_stdin = in ;
sb_out = malloc ( sizeof ( string_buffer_t ) ) ;
sb_err = malloc ( sizeof ( string_buffer_t ) ) ;
sb_init ( sb_out ) ;
2006-01-31 03:53:10 +08:00
sb_init ( sb_err ) ;
2005-09-20 21:26:39 +08:00
}
void builtin_pop_io ( )
{
builtin_stdin = 0 ;
sb_destroy ( sb_out ) ;
sb_destroy ( sb_err ) ;
free ( sb_out ) ;
free ( sb_err ) ;
2006-01-31 03:53:10 +08:00
2005-09-20 21:26:39 +08:00
if ( al_get_count ( & io_stack ) > 0 )
{
sb_err = ( string_buffer_t * ) al_pop ( & io_stack ) ;
sb_out = ( string_buffer_t * ) al_pop ( & io_stack ) ;
2006-08-01 00:23:39 +08:00
builtin_stdin = ( int ) al_pop_long ( & io_stack ) ;
2005-09-20 21:26:39 +08:00
}
else
{
sb_out = sb_err = 0 ;
builtin_stdin = 0 ;
}
}