2005-09-20 13:26:39 +00:00
/** \file builtin.c
Functions for executing builtin functions .
How to add a new builtin function :
1 ) . Create a function in builtin . c with the following signature :
< tt > static int builtin_NAME ( wchar_t * * args ) < / tt >
where NAME is the name of the builtin , and args is a zero - terminated list of arguments .
2 ) . Add a line like hash_put ( & builtin , L " NAME " , & builtin_NAME ) ; to builtin_init . This will enable the parser to find the builtin function .
2006-01-04 12:51:02 +00:00
3 ) . Add a line like hash_put ( desc , L " NAME " , _ ( L " Bla bla bla " ) ) ; to the proper part of builtin_get_desc , containing a short description of what the builtin does . This description is used by the completion system .
2005-09-20 13:26:39 +00:00
2005-12-11 23:39:39 +00:00
4 ) . Create a file doc_src / NAME . txt , containing the manual for the builtin in Doxygen - format . Check the other builtin manuals for proper syntax .
2005-09-20 13:26:39 +00:00
2005-12-11 23:39:39 +00:00
5 ) . Add an entry to the BUILTIN_DOC_SRC variable of Makefile . in . Note that the entries should be sorted alphabetically !
2005-09-20 13:26:39 +00:00
2005-12-11 23:39:39 +00:00
6 ) . Add an entry to the manual at the builtin - overview subsection . Note that the entries should be sorted alphabetically !
2005-09-20 13:26:39 +00:00
2005-12-14 23:48:08 +00:00
7 ) . Use ' darcs add doc_src / NAME . txt ' to start tracking changes to the documentation file .
2005-09-20 13:26:39 +00:00
*/
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <unistd.h>
# include <termios.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <dirent.h>
# include <string.h>
# include <signal.h>
# include <wctype.h>
# include <sys/time.h>
2005-09-24 19:55:58 +00:00
# include <time.h>
2005-09-20 13:26:39 +00:00
# include "config.h"
# include "util.h"
# 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 "expand.h"
# include "common.h"
# include "wgetopt.h"
# include "sanity.h"
# include "tokenizer.h"
# include "builtin_help.h"
# include "wildcard.h"
# include "input_common.h"
# include "input.h"
# include "intern.h"
2005-10-05 22:37:08 +00:00
# include "event.h"
2005-10-08 11:20:51 +00:00
# include "signal.h"
2006-01-04 12:51:02 +00:00
# include "translate.h"
2005-09-20 13:26:39 +00:00
/**
The default prompt for the read command
*/
# define DEFAULT_READ_PROMPT L"set_color green; echo read; set_color normal; echo \"> \""
/**
The mode name to pass to history and input
*/
# define READ_MODE_NAME L"fish_read"
2005-12-15 13:59:02 +00:00
2005-09-20 13:26:39 +00:00
/**
2005-12-15 13:59:02 +00:00
The send stuff to foreground message
2005-09-20 13:26:39 +00:00
*/
2006-01-04 12:51:02 +00:00
# define FG_MSG _( L"Send job %d, '%ls' to foreground\n" )
2005-12-11 23:30:01 +00:00
2005-12-15 13:59:02 +00:00
/**
Print modes for the jobs builtin
*/
enum
{
JOBS_DEFAULT , /**< Print lots of general info */
JOBS_PRINT_PID , /**< Print pid of each process in job */
JOBS_PRINT_COMMAND , /**< Print command name of each process in job */
JOBS_PRINT_GROUP , /**< Print group id of job */
}
2005-12-11 23:30:01 +00:00
;
2005-12-15 13:59:02 +00:00
/**
Table of all builtins
*/
2005-09-20 13:26:39 +00:00
static hash_table_t builtin ;
int builtin_out_redirect ;
int builtin_err_redirect ;
2005-12-15 13:59:02 +00:00
/*
2005-09-20 13:26:39 +00:00
Buffers for storing the output of builtin functions
*/
string_buffer_t * sb_out = 0 , * sb_err = 0 ;
2005-12-15 13:59:02 +00:00
2005-09-20 13:26:39 +00:00
/**
Stack containing builtin I / O for recursive builtin calls .
*/
static array_list_t io_stack ;
/**
The file from which builtin functions should attempt to read , use
instead of stdin .
*/
static int builtin_stdin ;
/**
Table containing descriptions for all builtins
*/
static hash_table_t * desc = 0 ;
int builtin_count_args ( wchar_t * * argv )
{
int argc = 1 ;
while ( argv [ argc ] ! = 0 )
{
argc + + ;
}
return argc ;
}
2005-10-14 22:33:01 +00:00
void builtin_wperror ( const wchar_t * s )
2005-09-20 13:26:39 +00:00
{
if ( s ! = 0 )
{
2005-09-30 18:28:26 +00:00
sb_append2 ( sb_err , s , L " : " , ( void * ) 0 ) ;
2005-09-20 13:26:39 +00:00
}
char * err = strerror ( errno ) ;
wchar_t * werr = str2wcs ( err ) ;
if ( werr )
{
2005-09-30 18:28:26 +00:00
sb_append2 ( sb_err , werr , L " \n " , ( void * ) 0 ) ;
2005-09-20 13:26:39 +00:00
free ( werr ) ;
}
}
/*
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 ' jobs ' is
' builtin_jobs ' .
Two builtins , ' command ' and ' builtin ' are not defined here as they
are part of the parser . ( They are not parsed as commands , instead
they only slightly alter the parser state )
*/
/**
Noop function . A fake function which successfully does nothing , for
builtins which are handled by the parser , such as command and
while .
*/
static int builtin_ignore ( wchar_t * * argv )
{
return 0 ;
}
void builtin_print_help ( wchar_t * cmd , string_buffer_t * b )
{
const char * h ;
if ( b = = sb_err )
{
sb_append ( sb_err ,
parser_current_line ( ) ) ;
}
h = builtin_help_get ( cmd ) ;
if ( ! h )
return ;
wchar_t * str = str2wcs ( builtin_help_get ( cmd ) ) ;
if ( str )
{
sb_append ( b , str ) ;
free ( str ) ;
}
}
/**
The bind builtin , used for setting character sequences
*/
static int builtin_bind ( wchar_t * * argv )
{
int i ;
int argc = builtin_count_args ( argv ) ;
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
L " set-mode " , required_argument , 0 , ' M '
}
,
{
0 , 0 , 0 , 0
}
}
;
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " M: " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
2006-01-04 12:51:02 +00:00
argv [ 0 ] ,
2005-09-20 13:26:39 +00:00
long_options [ opt_index ] . name ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case ' M ' :
input_set_mode ( woptarg ) ;
break ;
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
for ( i = woptind ; i < argc ; i + + )
{
input_parse_inputrc_line ( argv [ i ] ) ;
}
return 0 ;
}
2005-12-11 22:21:01 +00:00
/**
The block builtin , used for temporarily blocking events
*/
static int builtin_block ( wchar_t * * argv )
{
enum
{
UNSET ,
GLOBAL ,
LOCAL ,
}
;
int scope = UNSET ;
int erase = 0 ;
int argc = builtin_count_args ( argv ) ;
int type = ( 1 < < EVENT_ANY ) ;
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
L " erase " , no_argument , 0 , ' e '
}
,
{
L " local " , no_argument , 0 , ' l '
}
,
{
L " global " , no_argument , 0 , ' g '
}
,
{
L " help " , no_argument , 0 , ' h '
}
,
{
0 , 0 , 0 , 0
}
}
;
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " elgh " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-12-11 22:21:01 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 0 ;
case ' g ' :
scope = GLOBAL ;
break ;
case ' l ' :
scope = LOCAL ;
break ;
case ' e ' :
erase = 1 ;
break ;
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
if ( erase )
{
if ( scope ! = UNSET )
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err , _ ( L " %ls: Can not specify scope when removing block \n " ) , argv [ 0 ] ) ;
2005-12-11 22:21:01 +00:00
return 1 ;
}
if ( ! global_event_block )
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err , _ ( L " %ls: No blocks defined \n " ) , argv [ 0 ] ) ;
2005-12-11 22:21:01 +00:00
return 1 ;
}
event_block_t * eb = global_event_block ;
global_event_block = eb - > next ;
free ( eb ) ;
}
else
{
block_t * block = current_block ;
event_block_t * eb = malloc ( sizeof ( event_block_t ) ) ;
if ( ! eb )
die_mem ( ) ;
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 ;
}
else
{
eb - > next = global_event_block ;
global_event_block = eb ;
}
}
return 0 ;
}
2005-09-20 13:26:39 +00: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 ;
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
L " names " , no_argument , 0 , ' n '
}
,
{
L " help " , no_argument , 0 , ' h '
}
,
{
0 , 0 , 0 , 0
}
}
;
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " nh " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 0 ;
case ' n ' :
list = 1 ;
break ;
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
if ( list )
{
array_list_t names ;
wchar_t * * names_arr ;
int i ;
al_init ( & names ) ;
builtin_get_names ( & names ) ;
names_arr = list_to_char_arr ( & names ) ;
qsort ( names_arr ,
al_get_count ( & names ) ,
sizeof ( wchar_t * ) ,
( int ( * ) ( const void * , const void * ) ) & wcsfilecmp ) ;
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
if ( wcscmp ( names_arr [ i ] , L " count " ) = = 0 )
continue ;
sb_append2 ( sb_out ,
names_arr [ i ] ,
L " \n " ,
2005-09-30 18:28:26 +00:00
( void * ) 0 ) ;
2005-09-20 13:26:39 +00:00
}
free ( names_arr ) ;
al_destroy ( & names ) ;
}
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 '
}
,
{
0 , 0 , 0 , 0
}
}
;
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " h " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_out ) ;
return 0 ;
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
return 1 ;
}
/**
The exec bultin . This is only a placeholder that prints the help message . Ther actual implementation lives in exec . c .
*/
static int builtin_exec ( wchar_t * * argv )
{
int argc = builtin_count_args ( argv ) ;
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
L " help " , no_argument , 0 , ' h '
}
,
{
0 , 0 , 0 , 0
}
}
;
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " h " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_out ) ;
return 0 ;
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
return 1 ;
}
2006-01-23 20:40:14 +00:00
/**
Print the definitions of the given function to sb_out
stringbuffer . Used by the functions builtin .
*/
2005-12-17 12:25:46 +00:00
static void functions_def ( wchar_t * name )
{
const wchar_t * desc = function_get_desc ( name ) ;
const wchar_t * def = function_get_definition ( name ) ;
array_list_t ev ;
event_t search ;
int i ;
search . function_name = name ;
search . type = EVENT_ANY ;
al_init ( & ev ) ;
event_get ( & search , & ev ) ;
sb_append2 ( sb_out ,
L " function " ,
name ,
( void * ) 0 ) ;
if ( desc & & wcslen ( desc ) )
{
wchar_t * esc_desc = escape ( desc , 1 ) ;
sb_append2 ( sb_out , L " --description " , esc_desc , ( void * ) 0 ) ;
free ( esc_desc ) ;
}
for ( i = 0 ; i < al_get_count ( & ev ) ; i + + )
{
event_t * next = ( event_t * ) al_get ( & ev , i ) ;
switch ( next - > type )
{
case EVENT_SIGNAL :
{
sb_printf ( sb_out , L " --on-signal %ls " , sig2wcs ( next - > param1 . signal ) ) ;
break ;
}
case EVENT_VARIABLE :
{
sb_printf ( sb_out , L " --on-variable %ls " , next - > param1 . variable ) ;
break ;
}
case EVENT_EXIT :
{
if ( next - > param1 . pid > 0 )
sb_printf ( sb_out , L " --on-process-exit %d " , next - > param1 . pid ) ;
else
sb_printf ( sb_out , L " --on-job-exit %d " , - next - > param1 . pid ) ;
break ;
}
case EVENT_JOB_ID :
{
job_t * j = job_get ( next - > param1 . job_id ) ;
if ( j )
sb_printf ( sb_out , L " --on-job-exit %d " , j - > pgid ) ;
break ;
}
}
}
al_destroy ( & ev ) ;
sb_append2 ( sb_out ,
L " \n \t " ,
def ,
L " \n end \n \n " ,
( void * ) 0 ) ;
2006-01-14 01:58:01 +00:00
2005-12-17 12:25:46 +00:00
}
2005-09-20 13:26:39 +00:00
/**
The functions builtin , used for listing and erasing functions .
*/
static int builtin_functions ( wchar_t * * argv )
{
int i ;
int erase = 0 ;
wchar_t * desc = 0 ;
array_list_t names ;
wchar_t * * names_arr ;
int argc = builtin_count_args ( argv ) ;
int list = 0 ;
int show_hidden = 0 ;
2005-10-15 00:51:26 +00:00
int res = 0 ;
2005-09-20 13:26:39 +00:00
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
L " erase " , no_argument , 0 , ' e '
}
,
{
L " description " , required_argument , 0 , ' d '
}
,
{
L " names " , no_argument , 0 , ' n '
}
,
{
L " all " , no_argument , 0 , ' a '
}
,
{
0 , 0 , 0 , 0
}
}
;
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " ed:na " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case ' e ' :
erase = 1 ;
break ;
case ' d ' :
desc = woptarg ;
break ;
case ' n ' :
list = 1 ;
break ;
case ' a ' :
show_hidden = 1 ;
break ;
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
/*
Erase , desc and list are mutually exclusive
*/
if ( ( erase + ( desc ! = 0 ) + list ) > 1 )
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
_ ( L " %ls: Invalid combination of options \n " ) ,
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
if ( erase )
{
int i ;
for ( i = woptind ; i < argc ; i + + )
function_remove ( argv [ i ] ) ;
return 0 ;
}
else if ( desc )
{
wchar_t * func ;
if ( argc - woptind ! = 1 )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Expected exactly one function name \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
func = argv [ woptind ] ;
if ( ! function_exists ( func ) )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Function '%ls' does not exist \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
func ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
function_set_desc ( func , desc ) ;
return 0 ;
}
else if ( list )
{
2006-01-15 11:58:05 +00:00
int is_screen = ! builtin_out_redirect & & isatty ( 1 ) ;
2005-09-20 13:26:39 +00:00
al_init ( & names ) ;
function_get_names ( & names , show_hidden ) ;
names_arr = list_to_char_arr ( & names ) ;
qsort ( names_arr ,
al_get_count ( & names ) ,
sizeof ( wchar_t * ) ,
( int ( * ) ( const void * , const void * ) ) & wcsfilecmp ) ;
2006-01-15 11:58:05 +00:00
if ( is_screen )
2005-09-20 13:26:39 +00:00
{
2006-01-15 11:58:05 +00:00
string_buffer_t buff ;
sb_init ( & buff ) ;
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
sb_append2 ( & buff ,
names_arr [ i ] ,
L " , " ,
( void * ) 0 ) ;
}
write_screen ( ( wchar_t * ) buff . buff ) ;
sb_destroy ( & buff ) ;
}
else
{
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
sb_append2 ( sb_out ,
names_arr [ i ] ,
L " \n " ,
( void * ) 0 ) ;
}
2005-09-20 13:26:39 +00:00
}
2006-01-15 11:58:05 +00:00
2005-09-20 13:26:39 +00:00
free ( names_arr ) ;
al_destroy ( & names ) ;
return 0 ;
}
switch ( argc - woptind )
{
case 0 :
{
2006-01-04 12:51:02 +00:00
sb_append ( sb_out , _ ( L " Current function definitions are: \n \n " ) ) ;
2005-09-20 13:26:39 +00:00
al_init ( & names ) ;
function_get_names ( & names , show_hidden ) ;
names_arr = list_to_char_arr ( & names ) ;
qsort ( names_arr ,
al_get_count ( & names ) ,
sizeof ( wchar_t * ) ,
( int ( * ) ( const void * , const void * ) ) & wcsfilecmp ) ;
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
2005-12-17 12:25:46 +00:00
functions_def ( names_arr [ i ] ) ;
2005-09-20 13:26:39 +00:00
}
free ( names_arr ) ;
al_destroy ( & names ) ;
break ;
}
default :
{
2005-10-15 00:51:26 +00:00
2005-09-20 13:26:39 +00:00
for ( i = woptind ; i < argc ; i + + )
2005-10-15 00:51:26 +00:00
{
if ( ! function_exists ( argv [ i ] ) )
res + + ;
else
{
2005-12-17 12:25:46 +00:00
functions_def ( argv [ i ] ) ;
2005-10-15 00:51:26 +00:00
}
}
2005-09-20 13:26:39 +00:00
break ;
}
}
2005-10-15 00:51:26 +00:00
return res ;
2005-09-20 13:26:39 +00:00
}
2005-09-20 23:42:00 +00:00
/**
Test whether the specified string is a valid name for a keybinding
*/
static int wcsbindingname ( wchar_t * str )
{
while ( * str )
{
if ( ( ! iswalnum ( * str ) ) & & ( * str ! = L ' - ' ) )
{
return 0 ;
}
str + + ;
}
return 1 ;
}
2005-09-20 13:26:39 +00:00
2005-10-24 15:26:25 +00:00
/**
Debug function to print the current block stack
*/
2005-10-15 00:51:26 +00:00
static void print_block_stack ( block_t * b )
{
if ( ! b )
return ;
wprintf ( L " %ls (%d) \n " , parser_get_block_desc ( b - > type ) , b - > job ? b - > job - > job_id : - 1 ) ;
print_block_stack ( b - > outer ) ;
}
2005-09-20 13:26:39 +00:00
/**
The function builtin , used for providing subroutines .
It calls various functions from function . c to perform any heavy lifting .
*/
static int builtin_function ( wchar_t * * argv )
{
int argc = builtin_count_args ( argv ) ;
int res = 0 ;
wchar_t * desc = 0 ;
2005-09-20 23:42:00 +00:00
int is_binding = 0 ;
2005-10-05 22:37:08 +00:00
array_list_t * events = al_new ( ) ;
2005-09-20 13:26:39 +00:00
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
L " description " , required_argument , 0 , ' d '
}
,
2005-09-20 23:42:00 +00:00
{
L " key-binding " , no_argument , 0 , ' b '
}
,
2005-10-05 22:37:08 +00:00
{
L " on-signal " , required_argument , 0 , ' s '
}
,
{
2005-10-11 19:23:43 +00:00
L " on-job-exit " , required_argument , 0 , ' j '
}
,
{
L " on-process-exit " , required_argument , 0 , ' p '
2005-10-05 22:37:08 +00:00
}
,
{
L " on-variable " , required_argument , 0 , ' v '
}
,
2005-09-20 13:26:39 +00:00
{
0 , 0 , 0 , 0
}
}
;
2005-10-05 22:37:08 +00:00
while ( 1 & & ( ! res ) )
2005-09-20 13:26:39 +00:00
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
2005-10-11 19:23:43 +00:00
L " bd:s:j:p:v: " ,
2005-09-20 13:26:39 +00:00
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2005-10-05 22:37:08 +00:00
res = 1 ;
break ;
2005-09-20 13:26:39 +00:00
case ' d ' :
desc = woptarg ;
break ;
2005-09-20 23:42:00 +00:00
case ' b ' :
is_binding = 1 ;
break ;
2005-10-05 22:37:08 +00:00
case ' s ' :
{
2005-10-06 11:54:16 +00:00
int sig = wcs2sig ( woptarg ) ;
event_t * e ;
if ( sig < 0 )
{
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Unknown signal '%ls' \n " ) ,
2005-10-06 11:54:16 +00:00
argv [ 0 ] ,
woptarg ) ;
res = 1 ;
break ;
}
2005-12-11 22:21:01 +00:00
e = calloc ( 1 , sizeof ( event_t ) ) ;
2005-10-05 22:37:08 +00:00
if ( ! e )
die_mem ( ) ;
e - > type = EVENT_SIGNAL ;
2005-10-11 19:31:16 +00:00
e - > param1 . signal = sig ;
2005-10-05 22:37:08 +00:00
e - > function_name = 0 ;
al_push ( events , e ) ;
break ;
}
case ' v ' :
{
2005-10-06 11:54:16 +00:00
event_t * e ;
if ( ! wcsvarname ( woptarg ) )
{
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Invalid variable name '%ls' \n " ) ,
2005-10-06 11:54:16 +00:00
argv [ 0 ] ,
woptarg ) ;
res = 1 ;
break ;
}
2005-12-11 22:21:01 +00:00
e = calloc ( 1 , sizeof ( event_t ) ) ;
2005-10-05 22:37:08 +00:00
if ( ! e )
die_mem ( ) ;
e - > type = EVENT_VARIABLE ;
2005-10-11 19:31:16 +00:00
e - > param1 . variable = wcsdup ( woptarg ) ;
2005-10-05 22:37:08 +00:00
e - > function_name = 0 ;
al_push ( events , e ) ;
break ;
}
2005-10-11 19:23:43 +00:00
case ' j ' :
case ' p ' :
2005-10-05 22:37:08 +00:00
{
2005-10-06 11:54:16 +00:00
pid_t pid ;
wchar_t * end ;
event_t * e ;
2005-12-11 22:21:01 +00:00
e = calloc ( 1 , sizeof ( event_t ) ) ;
2005-10-05 22:37:08 +00:00
if ( ! e )
die_mem ( ) ;
2005-10-15 00:51:26 +00:00
if ( ( opt = = ' j ' ) & &
( wcscasecmp ( woptarg , L " caller " ) = = 0 ) )
{
int job_id = - 1 ;
if ( is_subshell )
{
block_t * b = current_block ;
// print_block_stack( b );
while ( b & & ( b - > type ! = SUBST ) )
b = b - > outer ;
if ( b )
{
b = b - > outer ;
}
if ( b - > job )
{
// debug( 1, L"Found block, type is %ls", parser_get_block_desc( b->type ) );
job_id = b - > job - > job_id ;
}
else
{
// debug( 1, L"Calling block is null" );
}
}
if ( job_id = = - 1 )
{
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Cannot find calling job for event handler \n " ) ,
2005-10-15 00:51:26 +00:00
argv [ 0 ] ) ;
res = 1 ;
}
else
{
e - > type = EVENT_JOB_ID ;
e - > param1 . job_id = job_id ;
}
}
else
{
errno = 0 ;
pid = wcstol ( woptarg , & end , 10 ) ;
if ( errno | | ! end | | * end )
{
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Invalid process id %ls \n " ) ,
2005-10-15 00:51:26 +00:00
argv [ 0 ] ,
woptarg ) ;
res = 1 ;
break ;
}
e - > type = EVENT_EXIT ;
e - > param1 . pid = ( opt = = ' j ' ? - 1 : 1 ) * abs ( pid ) ;
}
if ( res )
{
free ( e ) ;
}
else
{
e - > function_name = 0 ;
al_push ( events , e ) ;
}
2005-10-05 22:37:08 +00:00
break ;
}
2005-09-20 13:26:39 +00:00
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2005-10-05 22:37:08 +00:00
res = 1 ;
break ;
2005-09-20 13:26:39 +00:00
}
}
2005-10-05 22:37:08 +00:00
if ( ! res )
{
if ( argc - woptind ! = 1 )
{
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Expected one argument, got %d \n " ) ,
2005-10-05 22:37:08 +00:00
argv [ 0 ] ,
argc - woptind ) ;
res = 1 ;
}
else if ( ! ( is_binding ? wcsbindingname ( argv [ woptind ] ) : wcsvarname ( argv [ woptind ] ) ) )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Illegal function name '%ls' \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ woptind ] ) ;
2005-10-05 22:37:08 +00:00
res = 1 ;
}
else if ( parser_is_reserved ( argv [ woptind ] ) )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: The name '%ls' is reserved, \n and can not be used as a function name \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ woptind ] ) ;
2005-10-05 22:37:08 +00:00
res = 1 ;
}
2005-09-20 13:26:39 +00:00
}
if ( res )
{
int i ;
array_list_t names ;
wchar_t * * names_arr ;
int chars = 0 ;
2005-10-15 00:51:26 +00:00
// builtin_print_help( argv[0], sb_err );
2006-01-04 12:51:02 +00:00
const wchar_t * cfa = _ ( L " Current functions are: " ) ;
sb_append ( sb_err , cfa ) ;
chars + = wcslen ( cfa ) ;
2005-09-20 13:26:39 +00:00
al_init ( & names ) ;
function_get_names ( & names , 0 ) ;
names_arr = list_to_char_arr ( & names ) ;
qsort ( names_arr ,
al_get_count ( & names ) ,
sizeof ( wchar_t * ) ,
( int ( * ) ( const void * , const void * ) ) & wcsfilecmp ) ;
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
wchar_t * nxt = names_arr [ i ] ;
int l = wcslen ( nxt + 2 ) ;
2005-10-14 11:40:33 +00:00
if ( chars + l > common_get_width ( ) )
2005-09-20 13:26:39 +00:00
{
chars = 0 ;
sb_append ( sb_err , L " \n " ) ;
}
sb_append2 ( sb_err ,
2005-09-30 18:28:26 +00:00
nxt , L " " , ( void * ) 0 ) ;
2005-09-20 13:26:39 +00:00
}
free ( names_arr ) ;
al_destroy ( & names ) ;
sb_append ( sb_err , L " \n " ) ;
parser_push_block ( FAKE ) ;
2005-10-05 22:37:08 +00:00
al_foreach ( events , ( void ( * ) ( const void * ) ) & event_free ) ;
al_destroy ( events ) ;
2005-10-06 11:54:16 +00:00
free ( events ) ;
2005-09-20 13:26:39 +00:00
}
else
{
2005-10-05 22:37:08 +00:00
int i ;
2005-09-20 13:26:39 +00:00
parser_push_block ( FUNCTION_DEF ) ;
2005-10-11 19:31:16 +00:00
current_block - > param1 . function_name = wcsdup ( argv [ woptind ] ) ;
current_block - > param2 . function_description = desc ? wcsdup ( desc ) : 0 ;
current_block - > param3 . function_is_binding = is_binding ;
current_block - > param4 . function_events = events ;
2005-10-05 22:37:08 +00:00
for ( i = 0 ; i < al_get_count ( events ) ; i + + )
{
event_t * e = ( event_t * ) al_get ( events , i ) ;
2005-10-11 19:31:16 +00:00
e - > function_name = wcsdup ( current_block - > param1 . function_name ) ;
2005-10-05 22:37:08 +00:00
}
2005-09-20 13:26:39 +00:00
}
current_block - > tok_pos = parser_get_pos ( ) ;
current_block - > skip = 1 ;
return 0 ;
}
/**
The random builtin . For generating random numbers .
*/
static int builtin_random ( wchar_t * * argv )
{
static int seeded = 0 ;
int argc = builtin_count_args ( argv ) ;
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
L " help " , no_argument , 0 , ' h '
}
,
{
0 , 0 , 0 , 0
}
}
;
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " h " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
break ;
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
switch ( argc - woptind )
{
case 0 :
{
if ( ! seeded )
{
seeded = 1 ;
srand ( time ( 0 ) ) ;
}
sb_printf ( sb_out , L " %d \n " , rand ( ) % 32767 ) ;
break ;
}
case 1 :
{
int foo ;
wchar_t * end = 0 ;
errno = 0 ;
foo = wcstol ( argv [ woptind ] , & end , 10 ) ;
if ( errno | | * end )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Seed value '%ls' is not a valid number \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ woptind ] ) ;
2005-09-20 13:26:39 +00:00
return 1 ;
}
seeded = 1 ;
srand ( foo ) ;
break ;
}
default :
{
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Expected zero or one argument, got %d \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
2005-09-20 13:26:39 +00:00
argc - woptind ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
return 0 ;
}
/**
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 " " ;
woptind = 0 ;
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 12:26:40 +00:00
{
L " universal " , no_argument , 0 , ' U '
}
,
2005-09-20 13:26:39 +00:00
{
L " unexport " , no_argument , 0 , ' u '
}
,
{
L " prompt " , required_argument , 0 , ' p '
}
,
{
L " command " , required_argument , 0 , ' c '
}
,
{
0 , 0 , 0 , 0
}
}
;
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
2006-01-11 12:26:40 +00:00
L " xglUup:c: " ,
2005-09-20 13:26:39 +00:00
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case L ' x ' :
place | = ENV_EXPORT ;
break ;
case L ' g ' :
place | = ENV_GLOBAL ;
break ;
case L ' l ' :
place | = ENV_LOCAL ;
break ;
2006-01-11 12:26:40 +00:00
case L ' U ' :
place | = ENV_UNIVERSAL ;
break ;
2005-09-20 13:26:39 +00:00
case L ' u ' :
place | = ENV_UNEXPORT ;
break ;
case L ' p ' :
prompt = woptarg ;
break ;
case L ' c ' :
commandline = woptarg ;
break ;
case L ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
if ( ( place & ENV_UNEXPORT ) & & ( place & ENV_EXPORT ) )
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_EXPUNEXP ,
argv [ 0 ] ,
parser_current_line ( ) ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
2006-01-11 12:26:40 +00:00
if ( ( place & ENV_LOCAL ? 1 : 0 ) + ( place & ENV_GLOBAL ? 1 : 0 ) + ( place & ENV_UNIVERSAL ? 1 : 0 ) > 1 )
2005-09-20 13:26:39 +00:00
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_GLOCAL ,
argv [ 0 ] ,
parser_current_line ( ) ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
if ( woptind = = argc )
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_MISSING ,
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
sb_append2 ( sb_err ,
parser_current_line ( ) ,
L " \n " ,
2005-09-30 18:28:26 +00:00
( void * ) 0 ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
2005-12-07 16:06:47 +00:00
/*
Verify all variable names
*/
for ( i = woptind ; i < argc ; i + + )
{
wchar_t * src ;
if ( ! wcslen ( argv [ i ] ) )
{
sb_printf ( sb_err , BUILTIN_ERR_VARNAME_ZERO , argv [ 0 ] ) ;
return 1 ;
}
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 ) ;
return 1 ;
}
}
}
2005-09-20 13:26:39 +00:00
/*
The call to reader_readline may change woptind , so we save it away here
*/
i = woptind ;
ifs = env_get ( L " IFS " ) ;
if ( ifs = = 0 )
ifs = L " " ;
/*
Check if we should read interactively using \ c reader_readline ( )
*/
if ( isatty ( 0 ) & & builtin_stdin = = 0 )
{
reader_push ( READ_MODE_NAME ) ;
reader_set_prompt ( prompt ) ;
reader_set_buffer ( commandline , wcslen ( commandline ) ) ;
buff = wcsdup ( reader_readline ( ) ) ;
reader_pop ( ) ;
}
else
{
string_buffer_t sb ;
sb_init ( & sb ) ;
while ( 1 )
{
int eof = 0 ;
int finished = 0 ;
wchar_t res = 0 ;
static mbstate_t state ;
memset ( & state , ' \0 ' , sizeof ( state ) ) ;
while ( ! finished )
{
char b ;
int read_res = read_blocked ( builtin_stdin , & b , 1 ) ;
if ( read_res < = 0 )
{
eof = 1 ;
break ;
}
int sz = mbrtowc ( & res , & b , 1 , & state ) ;
switch ( sz )
{
case - 1 :
memset ( & state , ' \0 ' , sizeof ( state ) ) ;
break ;
case - 2 :
break ;
case 0 :
eof = 1 ;
finished = 1 ;
break ;
default :
finished = 1 ;
break ;
}
}
if ( eof )
break ;
if ( res = = L ' \n ' )
break ;
sb_append_char ( & sb , res ) ;
}
buff = wcsdup ( ( wchar_t * ) sb . buff ) ;
sb_destroy ( & sb ) ;
}
wchar_t * state ;
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 ) ;
}
free ( buff ) ;
return 0 ;
}
2005-10-24 15:26:25 +00:00
/**
The status builtin . Gives various status information on fish .
*/
2005-09-20 13:26:39 +00:00
static int builtin_status ( wchar_t * * argv )
{
enum
{
NORMAL ,
SUBST ,
BLOCK ,
INTERACTIVE ,
LOGIN
}
;
int mode = NORMAL ;
int argc = builtin_count_args ( argv ) ;
woptind = 0 ;
const static struct woption
long_options [ ] =
{
{
L " help " , no_argument , 0 , ' h '
}
,
{
L " is-command-substitution " , no_argument , 0 , ' c '
}
,
{
L " is-block " , no_argument , 0 , ' b '
}
,
{
L " is-interactive " , no_argument , 0 , ' i '
}
,
{
L " is-login " , no_argument , 0 , ' l '
}
,
{
0 , 0 , 0 , 0
}
}
;
while ( 1 )
{
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " hcbil " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
break ;
case ' i ' :
mode = INTERACTIVE ;
break ;
case ' c ' :
mode = SUBST ;
break ;
case ' b ' :
mode = BLOCK ;
break ;
case ' l ' :
mode = LOGIN ;
break ;
case ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
switch ( mode )
{
case INTERACTIVE :
return ! is_interactive_session ;
case SUBST :
return ! is_subshell ;
case BLOCK :
return ! is_block ;
case LOGIN :
return ! is_login ;
}
return 0 ;
}
/**
The eval builtin . Concatenates the arguments and calls eval on the
result .
*/
static int builtin_eval ( wchar_t * * argv )
{
2005-12-14 13:46:44 +00:00
string_buffer_t sb ;
int i ;
int argc = builtin_count_args ( argv ) ;
sb_init ( & sb ) ;
for ( i = 1 ; i < argc ; i + + )
2005-09-20 13:26:39 +00:00
{
2005-12-14 13:46:44 +00:00
sb_append ( & sb , argv [ i ] ) ;
sb_append ( & sb , L " " ) ;
2005-09-20 13:26:39 +00:00
}
2005-12-14 13:46:44 +00:00
eval ( ( wchar_t * ) sb . buff , block_io , TOP ) ;
sb_destroy ( & sb ) ;
2005-09-20 13:26:39 +00: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 )
{
int argc = builtin_count_args ( argv ) ;
int ec = 0 ;
switch ( argc )
{
case 1 :
break ;
case 2 :
{
wchar_t * end ;
errno = 0 ;
ec = wcstol ( argv [ 1 ] , & end , 10 ) ;
if ( errno | | * end ! = 0 )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-11 14:17:35 +00:00
_ ( L " %ls: Argument '%ls' must be an integer \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ 1 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
break ;
}
default :
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Too many arguments \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
reader_exit ( 1 ) ;
return ec ;
}
/**
Helper function for builtin_cd , used for seting the current working directory
*/
static int set_pwd ( wchar_t * env )
{
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 ;
if ( argv [ 1 ] = = 0 )
{
dir_in = env_get ( L " HOME " ) ;
if ( ! dir_in )
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
_ ( L " %ls: Could not find home directory \n " ) ,
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
}
}
else
dir_in = argv [ 1 ] ;
dir = parser_cdpath_get ( dir_in ) ;
if ( ! dir )
{
2005-12-16 15:51:16 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: '%ls' is not a directory or you do not have permission to enter it \n " ) ,
2005-12-16 15:51:16 +00:00
argv [ 0 ] ,
dir_in ) ;
2005-09-20 13:26:39 +00:00
sb_append2 ( sb_err ,
parser_current_line ( ) ,
2005-09-30 18:28:26 +00:00
( void * ) 0 ) ;
2005-09-20 13:26:39 +00:00
return 1 ;
}
if ( wchdir ( dir ) ! = 0 )
{
2005-12-16 15:51:16 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: '%ls' is not a directory \n " ) ,
2005-12-16 15:51:16 +00:00
argv [ 0 ] ,
dir ) ;
2005-09-20 13:26:39 +00:00
sb_append2 ( sb_err ,
parser_current_line ( ) ,
2005-09-30 18:28:26 +00:00
( void * ) 0 ) ;
2005-09-20 13:26:39 +00:00
free ( dir ) ;
return 1 ;
}
if ( ! set_pwd ( L " PWD " ) )
{
res = 1 ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err , _ ( L " %ls: Could not set PWD variable \n " ) , argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
}
free ( dir ) ;
return res ;
}
/**
2005-11-29 10:13:03 +00:00
The . ( dot ) builtin , sometimes called source . Evaluates the contents of a file .
2005-09-20 13:26:39 +00:00
*/
static int builtin_source ( wchar_t * * argv )
{
2005-10-19 12:07:44 +00:00
int fd ;
2005-09-20 13:26:39 +00:00
int res ;
2005-12-15 17:21:22 +00:00
struct stat buf ;
2005-12-16 15:51:16 +00:00
int argc ;
2005-09-20 13:26:39 +00:00
2005-12-16 15:51:16 +00:00
argc = builtin_count_args ( argv ) ;
if ( argc ! = 2 )
2005-09-20 13:26:39 +00:00
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err , _ ( L " %ls: Expected exactly one argument, got %d \n " ) , argv [ 0 ] , argc ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
2005-12-15 17:21:22 +00:00
if ( wstat ( argv [ 1 ] , & buf ) = = - 1 )
{
builtin_wperror ( L " stat " ) ;
2005-12-16 12:54:37 +00:00
return 1 ;
2005-12-15 17:21:22 +00:00
}
2005-12-16 12:54:37 +00:00
2005-12-15 17:21:22 +00:00
if ( ! S_ISREG ( buf . st_mode ) )
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err , _ ( L " %ls: '%ls' is not a file \n " ) , argv [ 0 ] , argv [ 1 ] ) ;
2005-12-15 17:21:22 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2005-12-16 15:51:16 +00:00
2005-12-15 17:21:22 +00:00
return 1 ;
}
2005-10-19 12:07:44 +00:00
if ( ( fd = wopen ( argv [ 1 ] , O_RDONLY ) ) = = - 1 )
2005-09-20 13:26:39 +00:00
{
builtin_wperror ( L " open " ) ;
res = 1 ;
}
else
{
reader_push_current_filename ( argv [ 1 ] ) ;
2005-10-19 12:07:44 +00:00
/*
Push a new non - shadowwing variable scope to the stack . That
way one can use explicitly local variables in sourced files
that will die on return to the calling file .
*/
2005-10-07 21:28:44 +00:00
env_push ( 0 ) ;
2005-10-19 12:07:44 +00:00
res = reader_read ( fd ) ;
2005-10-07 21:28:44 +00:00
env_pop ( ) ;
2005-09-20 13:26:39 +00:00
if ( res )
{
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Error while reading file '%ls' \n " ) ,
2005-09-20 13:26:39 +00:00
argv [ 0 ] ,
argv [ 1 ]
) ;
}
2005-10-19 12:07:44 +00:00
/*
Do not close fd after calling reader_read . reader_read
automatically closes it before calling eval .
*/
2005-09-20 13:26:39 +00:00
2005-10-19 12:07:44 +00:00
reader_pop_current_filename ( ) ;
2005-09-20 13:26:39 +00:00
}
return res ;
}
/**
Make the specified job the first job of the job list . Moving jobs
around in the list makes the list reflect the order in which the
2005-10-08 09:33:10 +00:00
jobs were used .
2005-09-20 13:26:39 +00:00
*/
static void make_first ( job_t * j )
{
job_t * prev = 0 ;
job_t * curr ;
for ( curr = first_job ; curr ! = j ; curr = curr - > next )
{
prev = curr ;
}
if ( curr = = j )
{
if ( prev = = 0 )
return ;
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 )
{
job_t * j ;
2006-01-19 12:22:07 +00:00
2005-09-20 13:26:39 +00:00
if ( argv [ 1 ] = = 0 )
{
/*
2006-01-22 21:10:55 +00:00
Select last constructed job ( I . e . first job in the job que ) that is possible to put in the foreground
2005-09-20 13:26:39 +00:00
*/
2006-01-19 13:15:15 +00:00
for ( j = first_job ; j ; j = j - > next )
{
if ( j - > constructed & & ( ! job_is_completed ( j ) ) & & ( job_is_stopped ( j ) | | ! j - > fg ) )
break ;
}
2006-01-18 16:47:50 +00:00
if ( ! j )
{
sb_printf ( sb_err ,
2006-01-19 13:15:15 +00:00
_ ( L " %ls: There are no suitable jobs \n " ) ,
2006-01-18 16:47:50 +00:00
argv [ 0 ] ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
}
2005-09-20 13:26:39 +00:00
}
else if ( argv [ 2 ] ! = 0 )
{
/*
Specifying what more than one job to put to the foreground
is a syntax error , we still try to locate the job argv [ 1 ] ,
since we want to know if this is an ambigous job
specification or if this is an malformed job id
*/
int pid = wcstol ( argv [ 1 ] , 0 , 10 ) ;
j = job_get_from_pid ( pid ) ;
if ( j ! = 0 )
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
_ ( L " %ls: Ambiguous job \n " ) ,
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
}
else
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
_ ( L " %ls: '%ls' is not a job \n " ) ,
argv [ 0 ] ,
argv [ 1 ] ) ;
2005-09-20 13:26:39 +00:00
}
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-01-19 13:15:15 +00:00
j = 0 ;
2005-09-20 13:26:39 +00:00
}
else
{
int pid = abs ( wcstol ( argv [ 1 ] , 0 , 10 ) ) ;
j = job_get_from_pid ( pid ) ;
2006-01-19 13:15:15 +00:00
if ( ! j )
{
sb_printf ( sb_err ,
_ ( L " %ls: No suitable job: %d \n " ) ,
argv [ 0 ] ,
pid ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
}
2005-09-20 13:26:39 +00:00
}
2006-01-19 13:15:15 +00:00
if ( j )
2005-09-20 13:26:39 +00:00
{
if ( builtin_err_redirect )
{
sb_printf ( sb_err ,
2005-12-15 13:59:02 +00:00
FG_MSG ,
2005-09-20 13:26:39 +00:00
j - > job_id ,
j - > command ) ;
}
else
{
2005-12-15 13:59:02 +00:00
/*
If we aren ' t redirecting , send output to real stderr ,
since stuff in sb_err won ' t get printed until the
command finishes .
*/
2005-09-20 13:26:39 +00:00
fwprintf ( stderr ,
2005-12-15 13:59:02 +00:00
FG_MSG ,
2005-09-20 13:26:39 +00:00
j - > job_id ,
j - > command ) ;
}
2005-12-15 13:59:02 +00:00
2006-01-19 13:15:15 +00:00
wchar_t * ft = tok_first ( j - > command ) ;
if ( ft ! = 0 )
env_set ( L " _ " , ft , ENV_EXPORT ) ;
free ( ft ) ;
reader_write_title ( ) ;
2005-09-20 13:26:39 +00:00
2006-01-19 13:15:15 +00:00
make_first ( j ) ;
j - > fg = 1 ;
job_continue ( j , job_is_stopped ( j ) ) ;
}
return j ! = 0 ;
2005-09-20 13:26:39 +00:00
}
/**
Helper function for builtin_bg ( )
*/
2006-01-19 13:15:15 +00:00
static int send_to_bg ( job_t * j , const wchar_t * name )
2005-09-20 13:26:39 +00:00
{
if ( j = = 0 )
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
_ ( L " %ls: Unknown job '%ls' \n " ) ,
L " bg " ,
name ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( L " bg " , sb_err ) ;
2006-01-19 13:15:15 +00:00
return 1 ;
2005-09-20 13:26:39 +00:00
}
else
{
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " Send job %d '%ls' to background \n " ) ,
2005-09-20 13:26:39 +00:00
j - > job_id ,
j - > command ) ;
}
make_first ( j ) ;
j - > fg = 0 ;
job_continue ( j , job_is_stopped ( j ) ) ;
2006-01-19 13:15:15 +00:00
return 0 ;
2005-09-20 13:26:39 +00:00
}
/**
Builtin for putting a job in the background
*/
static int builtin_bg ( wchar_t * * argv )
{
2006-01-19 13:15:15 +00:00
int res = 0 ;
2005-09-20 13:26:39 +00:00
if ( argv [ 1 ] = = 0 )
{
job_t * j ;
2006-01-19 13:15:15 +00:00
for ( j = first_job ; j ; j = j - > next )
{
if ( job_is_stopped ( j ) )
break ;
}
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 13:26:39 +00:00
}
2006-01-19 13:15:15 +00:00
else
2005-09-20 13:26:39 +00:00
{
2006-01-19 13:15:15 +00: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 13:26:39 +00:00
}
2006-01-19 13:15:15 +00:00
return res ;
2005-09-20 13:26:39 +00:00
}
# ifdef HAVE__PROC_SELF_STAT
/**
Calculates the cpu usage ( in percent ) of the specified job .
*/
static int cpu_use ( job_t * j )
{
double u = 0 ;
process_t * p ;
for ( p = j - > first_process ; p ; p = p - > next )
{
struct timeval t ;
int jiffies ;
gettimeofday ( & t , 0 ) ;
jiffies = proc_get_jiffies ( p ) ;
double t1 = 1000000.0 * p - > last_time . tv_sec + p - > last_time . tv_usec ;
double t2 = 1000000.0 * t . tv_sec + t . tv_usec ;
/* fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n",
t1 , t2 , jiffies , p - > last_jiffies ) ;
*/
u + = ( ( double ) ( jiffies - p - > last_jiffies ) ) / ( t2 - t1 ) ;
}
return u * 1000000 ;
}
# endif
2006-01-23 20:40:14 +00:00
/**
Print information about the specified job
*/
2005-12-11 23:30:01 +00:00
static void builtin_jobs_print ( job_t * j , int mode , int header )
{
process_t * p ;
switch ( mode )
{
case JOBS_DEFAULT :
{
if ( header )
{
/*
Print table header before first job
*/
2006-01-04 12:51:02 +00:00
sb_append ( sb_out , _ ( L " Job \t Group \t " ) ) ;
2005-12-11 23:30:01 +00:00
# ifdef HAVE__PROC_SELF_STAT
2006-01-04 12:51:02 +00:00
sb_append ( sb_out , _ ( L " CPU \t " ) ) ;
2005-12-11 23:30:01 +00:00
# endif
2006-01-04 12:51:02 +00:00
sb_append ( sb_out , _ ( L " State \t Command \n " ) ) ;
2005-12-11 23:30:01 +00:00
}
sb_printf ( sb_out , L " %d \t %d \t " , j - > job_id , j - > pgid ) ;
# ifdef HAVE__PROC_SELF_STAT
sb_printf ( sb_out , L " %d%% \t " , cpu_use ( j ) ) ;
# endif
2006-01-04 12:51:02 +00:00
sb_append2 ( sb_out ,
job_is_stopped ( j ) ? _ ( L " stopped " ) : _ ( L " running " ) ,
L " \t " ,
j - > command ,
L " \n " ,
( void * ) 0 ) ;
2005-12-12 15:50:01 +00:00
break ;
2005-12-11 23:30:01 +00:00
}
case JOBS_PRINT_GROUP :
{
if ( header )
{
/*
Print table header before first job
*/
2006-01-04 12:51:02 +00:00
sb_append ( sb_out , _ ( L " Group \n " ) ) ;
2005-12-11 23:30:01 +00:00
}
sb_printf ( sb_out , L " %d \n " , j - > pgid ) ;
break ;
}
case JOBS_PRINT_PID :
{
if ( header )
{
/*
Print table header before first job
*/
2006-01-04 12:51:02 +00:00
sb_append ( sb_out , _ ( L " Procces \n " ) ) ;
2005-12-11 23:30:01 +00:00
}
for ( p = j - > first_process ; p ; p = p - > next )
{
sb_printf ( sb_out , L " %d \n " , p - > pid ) ;
}
break ;
}
case JOBS_PRINT_COMMAND :
{
if ( header )
{
/*
Print table header before first job
*/
2006-01-04 12:51:02 +00:00
sb_append ( sb_out , _ ( L " Command \n " ) ) ;
2005-12-11 23:30:01 +00:00
}
for ( p = j - > first_process ; p ; p = p - > next )
{
sb_printf ( sb_out , L " %ls \n " , p - > argv [ 0 ] ) ;
}
break ;
2005-12-12 15:50:01 +00:00
}
2005-12-11 23:30:01 +00:00
}
}
2005-09-20 13:26:39 +00:00
/**
Builtin for printing running jobs
*/
static int builtin_jobs ( wchar_t * * argv )
{
int argc = 0 ;
int found = 0 ;
2005-12-11 23:30:01 +00:00
int mode = JOBS_DEFAULT ;
2005-12-12 15:50:01 +00:00
int print_last = 0 ;
job_t * j ;
2005-12-11 23:30:01 +00:00
2005-09-20 13:26:39 +00:00
argc = builtin_count_args ( argv ) ;
woptind = 0 ;
while ( 1 )
{
const static struct woption
long_options [ ] =
{
{
L " pid " , no_argument , 0 , ' p '
}
,
{
L " command " , no_argument , 0 , ' c '
}
,
2005-12-11 23:30:01 +00:00
{
L " group " , no_argument , 0 , ' g '
}
,
{
L " last " , no_argument , 0 , ' l '
}
,
2005-09-20 13:26:39 +00:00
{
0 , 0 , 0 , 0
}
}
;
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
2005-12-11 23:30:01 +00:00
L " pclg " ,
2005-09-20 13:26:39 +00:00
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-12-15 13:59:02 +00:00
2005-09-20 13:26:39 +00:00
sb_append ( sb_err ,
parser_current_line ( ) ) ;
// builtin_print_help( argv[0], sb_err );
return 1 ;
case ' p ' :
2005-12-11 23:30:01 +00:00
mode = JOBS_PRINT_PID ;
2005-09-20 13:26:39 +00:00
break ;
case ' c ' :
2005-12-11 23:30:01 +00:00
mode = JOBS_PRINT_COMMAND ;
break ;
case ' g ' :
mode = JOBS_PRINT_GROUP ;
break ;
case ' l ' :
{
2005-12-12 15:50:01 +00:00
print_last = 1 ;
2005-09-20 13:26:39 +00:00
break ;
2005-12-11 23:30:01 +00:00
}
2005-09-20 13:26:39 +00:00
case ' ? ' :
// builtin_print_help( argv[0], sb_err );
return 1 ;
}
}
2005-12-12 15:50:01 +00:00
/*
Do not babble if not interactive
*/
if ( builtin_out_redirect )
2005-09-20 13:26:39 +00:00
{
2005-12-12 15:50:01 +00:00
found = 1 ;
2005-09-20 13:26:39 +00:00
}
2005-12-11 23:30:01 +00:00
2005-12-12 15:50:01 +00:00
if ( print_last )
2005-09-20 13:26:39 +00:00
{
2005-12-12 15:50:01 +00:00
/*
Ignore unconstructed jobs , i . e . ourself .
*/
for ( j = first_job ; j ; j = j - > next )
2005-09-20 13:26:39 +00:00
{
2005-12-12 15:50:01 +00:00
if ( j - > constructed )
{
builtin_jobs_print ( j , mode , ! found ) ;
return 0 ;
}
2005-09-20 13:26:39 +00:00
}
2005-12-11 23:30:01 +00:00
}
2005-12-12 15:50:01 +00:00
else
2005-12-11 23:30:01 +00:00
{
2005-12-12 15:50:01 +00:00
if ( woptind < argc )
2005-09-20 13:26:39 +00:00
{
2005-12-12 15:50:01 +00:00
int i ;
found = 1 ;
for ( i = woptind ; i < argc ; i + + )
2005-09-20 13:26:39 +00:00
{
2005-12-12 15:50:01 +00:00
long pid ;
wchar_t * end ;
errno = 0 ;
pid = wcstol ( argv [ i ] , & end , 10 ) ;
if ( errno | | * end )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-11 14:17:35 +00:00
_ ( L " %ls: '%ls' is not a job \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ i ] ) ;
2005-12-12 15:50:01 +00:00
return 1 ;
}
j = job_get_from_pid ( pid ) ;
if ( j )
{
builtin_jobs_print ( j , mode , ! found ) ;
}
else
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: No suitable job: %d \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
pid ) ;
2005-12-12 15:50:01 +00:00
return 1 ;
}
2005-09-20 13:26:39 +00:00
}
2005-12-11 23:30:01 +00:00
}
2005-12-12 15:50:01 +00:00
else
2005-12-11 23:30:01 +00:00
{
2005-12-12 15:50:01 +00:00
for ( j = first_job ; j ; j = j - > next )
{
/*
Ignore unconstructed jobs , i . e . ourself .
*/
if ( j - > constructed /*&& j->skip_notification*/ )
{
builtin_jobs_print ( j , mode , ! found ) ;
found = 1 ;
}
}
2005-12-11 23:30:01 +00:00
}
}
2005-12-12 15:50:01 +00:00
if ( ! found )
2005-12-11 23:30:01 +00:00
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_out ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: There are no jobs \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
}
return 0 ;
}
/**
Builtin for looping over a list
*/
static int builtin_for ( wchar_t * * argv )
{
int argc = builtin_count_args ( argv ) ;
int res = 1 ;
if ( argc < 3 )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Expected at least two arguments \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
}
else if ( ! wcsvarname ( argv [ 1 ] ) )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-11 14:17:35 +00:00
_ ( L " %ls: '%ls' is not a valid variable name \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ 1 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
}
else if ( wcscmp ( argv [ 2 ] , L " in " ) ! = 0 )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Second argument must be 'in' \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
}
else
{
res = 0 ;
}
if ( res )
{
parser_push_block ( FAKE ) ;
}
else
{
parser_push_block ( FOR ) ;
2005-10-11 19:31:16 +00:00
al_init ( & current_block - > param2 . for_vars ) ;
2005-09-20 13:26:39 +00:00
int i ;
current_block - > tok_pos = parser_get_pos ( ) ;
2005-10-11 19:31:16 +00:00
current_block - > param1 . for_variable = wcsdup ( argv [ 1 ] ) ;
2005-09-20 13:26:39 +00:00
for ( i = argc - 1 ; i > 3 ; i - - )
{
2005-10-11 19:31:16 +00:00
al_push ( & current_block - > param2 . for_vars , wcsdup ( argv [ i ] ) ) ;
2005-09-20 13:26:39 +00:00
}
if ( argc > 3 )
{
2005-10-11 19:31:16 +00:00
env_set ( current_block - > param1 . for_variable , argv [ 3 ] , ENV_LOCAL ) ;
2005-09-20 13:26:39 +00:00
}
else
{
current_block - > skip = 1 ;
}
}
return res ;
}
2005-10-24 15:26:25 +00:00
/**
The begin builtin . Creates a nex block .
*/
2005-09-20 13:26:39 +00:00
static int builtin_begin ( wchar_t * * argv )
{
parser_push_block ( BEGIN ) ;
current_block - > tok_pos = parser_get_pos ( ) ;
return 0 ;
}
/**
Builtin for ending a block of code , such as a for - loop or an if statement .
The end command is whare a lot of the block - level magic happens .
*/
static int builtin_end ( wchar_t * * argv )
{
2006-01-05 15:37:53 +00:00
if ( ! current_block - > outer )
2005-09-20 13:26:39 +00:00
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Not inside of block \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
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 ;
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-11 19:31:16 +00:00
current_block - > param1 . while_state = WHILE_TEST_AGAIN ;
2005-09-20 13:26:39 +00:00
}
break ;
}
case IF :
case SUBST :
case BEGIN :
/*
Nothing special happens at the end of these . The scope just ends .
*/
break ;
case FOR :
{
/*
set loop variable to next element , and rewind to the beginning of the block .
*/
if ( current_block - > loop_status = = LOOP_BREAK )
{
2005-10-11 19:31:16 +00:00
while ( al_get_count ( & current_block - > param2 . for_vars ) )
2005-09-20 13:26:39 +00:00
{
2005-10-11 19:31:16 +00:00
free ( ( void * ) al_pop ( & current_block - > param2 . for_vars ) ) ;
2005-09-20 13:26:39 +00:00
}
}
2005-10-11 19:31:16 +00:00
if ( al_get_count ( & current_block - > param2 . for_vars ) )
2005-09-20 13:26:39 +00:00
{
2005-10-11 19:31:16 +00: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 13:26:39 +00:00
current_block - > loop_status = LOOP_NORMAL ;
current_block - > skip = 0 ;
free ( val ) ;
kill_block = 0 ;
parser_set_pos ( current_block - > tok_pos ) ;
/*
fwprintf ( stderr ,
L " jump to %d \n " ,
current_block - > tok_pos ) ; */
}
break ;
}
case FUNCTION_DEF :
{
/**
Copy the text from the beginning of the function
until the end command and use as the new definition
for the specified function
*/
wchar_t * def = wcsndup ( parser_get_buffer ( ) + current_block - > tok_pos ,
parser_get_job_pos ( ) - current_block - > tok_pos ) ;
//fwprintf( stderr, L"Function: %ls\n", def );
2005-11-02 15:41:59 +00:00
if ( ! is_interactive | | ! parser_test ( def , 1 ) )
2005-09-20 13:26:39 +00:00
{
2005-10-11 19:31:16 +00:00
function_add ( current_block - > param1 . function_name ,
2005-09-20 13:26:39 +00:00
def ,
2005-10-11 19:31:16 +00:00
current_block - > param2 . function_description ,
current_block - > param4 . function_events ,
current_block - > param3 . function_is_binding ) ;
2005-10-05 22:37:08 +00:00
}
2005-09-20 13:26:39 +00:00
free ( def ) ;
}
break ;
}
if ( kill_block )
{
parser_pop_block ( ) ;
}
/*
If everything goes ok , return status of last command to execute .
*/
return proc_get_last_status ( ) ;
}
}
/**
Builtin for executing commands if an if statement is false
*/
static int builtin_else ( wchar_t * * argv )
{
if ( current_block = = 0 | |
current_block - > type ! = IF | |
2005-10-11 19:31:16 +00:00
current_block - > param1 . if_state ! = 1 )
2005-09-20 13:26:39 +00:00
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Not inside of 'if' block \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
else
{
2005-10-11 19:31:16 +00:00
current_block - > param1 . if_state + + ;
2005-09-20 13:26:39 +00: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 ) ;
block_t * b = current_block ;
if ( argc ! = 1 )
{
2006-01-04 12:51:02 +00:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
2005-12-15 13:59:02 +00:00
argv [ 1 ] ) ;
2006-01-04 12:51:02 +00:00
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
while ( ( b ! = 0 ) & &
( b - > type ! = WHILE ) & &
( b - > type ! = FOR ) )
{
b = b - > outer ;
}
if ( b = = 0 )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Not inside of loop \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
b = current_block ;
while ( ( b - > type ! = WHILE ) & &
( 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 ) ;
int status = 0 ;
block_t * b = current_block ;
switch ( argc )
{
case 1 :
break ;
case 2 :
{
wchar_t * end ;
errno = 0 ;
status = wcstol ( argv [ 1 ] , & end , 10 ) ;
if ( errno | | * end ! = 0 )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-11 14:17:35 +00:00
_ ( L " %ls: Argument '%ls' must be an integer \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ,
argv [ 1 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
// fwprintf( stderr, L"Return with status %d\n", status );
break ;
}
default :
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Too many arguments \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
while ( ( b ! = 0 ) & &
( b - > type ! = FUNCTION_CALL ) )
{
b = b - > outer ;
}
if ( b = = 0 )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Not inside of function \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
b = current_block ;
while ( ( b - > type ! = FUNCTION_CALL ) )
{
b - > skip = 1 ;
b = b - > outer ;
}
b - > skip = 1 ;
// proc_set_last_status( status );
return status ;
}
/**
Builtin for executing one of several blocks of commands depending on the value of an argument .
*/
static int builtin_switch ( wchar_t * * argv )
{
int res = 0 ;
int argc = builtin_count_args ( argv ) ;
if ( argc ! = 2 )
{
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: Expected exactly one argument, got %d \n " ) ,
2005-09-20 13:26:39 +00:00
argv [ 0 ] ,
argc - 1 ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
res = 1 ;
parser_push_block ( FAKE ) ;
}
else
{
parser_push_block ( SWITCH ) ;
2005-10-11 19:31:16 +00:00
current_block - > param1 . switch_value = wcsdup ( argv [ 1 ] ) ;
2005-09-20 13:26:39 +00:00
current_block - > skip = 1 ;
2005-10-11 19:31:16 +00:00
current_block - > param2 . switch_taken = 0 ;
2005-09-20 13:26:39 +00:00
}
return res ;
}
/**
Builtin used together with the switch builtin for conditional execution
*/
static int builtin_case ( wchar_t * * argv )
{
int argc = builtin_count_args ( argv ) ;
int i ;
wchar_t * unescaped = 0 ;
if ( current_block - > type ! = SWITCH )
{
2005-12-15 13:59:02 +00:00
sb_printf ( sb_err ,
2006-01-04 12:51:02 +00:00
_ ( L " %ls: 'case' command while not in switch block \n " ) ,
2005-12-15 13:59:02 +00:00
argv [ 0 ] ) ;
2006-01-11 14:17:35 +00:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2005-09-20 13:26:39 +00:00
return 1 ;
}
current_block - > skip = 1 ;
2005-10-11 19:31:16 +00:00
if ( current_block - > param2 . switch_taken )
2005-09-20 13:26:39 +00:00
{
return 0 ;
}
for ( i = 1 ; i < argc ; i + + )
{
free ( unescaped ) ;
2005-10-07 10:36:51 +00:00
unescaped = expand_unescape ( argv [ i ] , 1 ) ;
2005-09-20 13:26:39 +00:00
2005-10-11 19:31:16 +00:00
if ( wildcard_match ( current_block - > param1 . switch_value , unescaped ) )
2005-09-20 13:26:39 +00:00
{
current_block - > skip = 0 ;
2005-10-11 19:31:16 +00:00
current_block - > param2 . switch_taken = 1 ;
2005-09-20 13:26:39 +00:00
break ;
}
}
free ( unescaped ) ;
return 0 ;
}
/*
END OF BUILTIN COMMANDS
Below are functions for handling the builtin commands
*/
2005-12-15 13:59:02 +00:00
2005-09-20 13:26:39 +00:00
void builtin_init ( )
{
al_init ( & io_stack ) ;
hash_init ( & builtin , & hash_wcs_func , & hash_wcs_cmp ) ;
2005-10-11 19:31:16 +00:00
hash_put ( & builtin , L " exit " , ( void * ) & builtin_exit ) ;
2005-12-11 22:21:01 +00:00
hash_put ( & builtin , L " block " , ( void * ) & builtin_block ) ;
2005-10-11 19:31:16 +00:00
hash_put ( & builtin , L " builtin " , ( void * ) & builtin_builtin ) ;
hash_put ( & builtin , L " cd " , ( void * ) & builtin_cd ) ;
hash_put ( & builtin , L " function " , ( void * ) & builtin_function ) ;
hash_put ( & builtin , L " functions " , ( void * ) & builtin_functions ) ;
hash_put ( & builtin , L " complete " , ( void * ) & builtin_complete ) ;
hash_put ( & builtin , L " end " , ( void * ) & builtin_end ) ;
hash_put ( & builtin , L " else " , ( void * ) & builtin_else ) ;
hash_put ( & builtin , L " eval " , ( void * ) & builtin_eval ) ;
hash_put ( & builtin , L " for " , ( void * ) & builtin_for ) ;
hash_put ( & builtin , L " . " , ( void * ) & builtin_source ) ;
hash_put ( & builtin , L " set " , ( void * ) & builtin_set ) ;
hash_put ( & builtin , L " fg " , ( void * ) & builtin_fg ) ;
hash_put ( & builtin , L " bg " , ( void * ) & builtin_bg ) ;
hash_put ( & builtin , L " jobs " , ( void * ) & builtin_jobs ) ;
hash_put ( & builtin , L " read " , ( void * ) & builtin_read ) ;
hash_put ( & builtin , L " break " , ( void * ) & builtin_break_continue ) ;
hash_put ( & builtin , L " continue " , ( void * ) & builtin_break_continue ) ;
hash_put ( & builtin , L " return " , ( void * ) & builtin_return ) ;
hash_put ( & builtin , L " commandline " , ( void * ) & builtin_commandline ) ;
hash_put ( & builtin , L " switch " , ( void * ) & builtin_switch ) ;
hash_put ( & builtin , L " case " , ( void * ) & builtin_case ) ;
hash_put ( & builtin , L " bind " , ( void * ) & builtin_bind ) ;
hash_put ( & builtin , L " random " , ( void * ) & builtin_random ) ;
hash_put ( & builtin , L " status " , ( void * ) & builtin_status ) ;
2005-10-14 22:33:01 +00:00
hash_put ( & builtin , L " ulimit " , ( void * ) & builtin_ulimit ) ;
2005-09-20 13:26:39 +00: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-10-11 19:31:16 +00:00
hash_put ( & builtin , L " command " , ( void * ) & builtin_ignore ) ;
hash_put ( & builtin , L " if " , ( void * ) & builtin_ignore ) ;
hash_put ( & builtin , L " while " , ( void * ) & builtin_ignore ) ;
hash_put ( & builtin , L " not " , ( void * ) & builtin_generic ) ;
hash_put ( & builtin , L " and " , ( void * ) & builtin_generic ) ;
hash_put ( & builtin , L " or " , ( void * ) & builtin_generic ) ;
hash_put ( & builtin , L " exec " , ( void * ) & builtin_exec ) ;
hash_put ( & builtin , L " begin " , ( void * ) & builtin_begin ) ;
2005-09-20 13:26:39 +00:00
/*
This is not a builtin , but fish handles it ' s help display
internally , to do some ugly special casing to make sure ' count
- h ' , but ' count ( echo - h ) ' does not .
*/
2005-10-11 19:31:16 +00:00
hash_put ( & builtin , L " count " , ( void * ) & builtin_ignore ) ;
2005-09-20 13:26:39 +00:00
intern_static ( L " exit " ) ;
intern_static ( L " builtin " ) ;
2005-12-11 22:21:01 +00:00
intern_static ( L " block " ) ;
2005-09-20 13:26:39 +00:00
intern_static ( L " cd " ) ;
intern_static ( L " function " ) ;
intern_static ( L " functions " ) ;
intern_static ( L " complete " ) ;
intern_static ( L " end " ) ;
intern_static ( L " else " ) ;
intern_static ( L " eval " ) ;
intern_static ( L " for " ) ;
intern_static ( L " . " ) ;
intern_static ( L " set " ) ;
intern_static ( L " fg " ) ;
intern_static ( L " bg " ) ;
intern_static ( L " jobs " ) ;
intern_static ( L " read " ) ;
intern_static ( L " break " ) ;
intern_static ( L " continue " ) ;
intern_static ( L " return " ) ;
intern_static ( L " commandline " ) ;
intern_static ( L " switch " ) ;
intern_static ( L " case " ) ;
intern_static ( L " bind " ) ;
intern_static ( L " random " ) ;
intern_static ( L " command " ) ;
intern_static ( L " if " ) ;
intern_static ( L " while " ) ;
intern_static ( L " exec " ) ;
intern_static ( L " count " ) ;
intern_static ( L " not " ) ;
intern_static ( L " and " ) ;
intern_static ( L " or " ) ;
intern_static ( L " begin " ) ;
intern_static ( L " status " ) ;
2005-10-14 22:33:01 +00:00
intern_static ( L " ulimit " ) ;
2005-09-20 13:26:39 +00:00
builtin_help_init ( ) ;
}
void builtin_destroy ( )
{
if ( desc )
{
hash_destroy ( desc ) ;
free ( desc ) ;
}
al_destroy ( & io_stack ) ;
hash_destroy ( & builtin ) ;
builtin_help_destroy ( ) ;
}
int builtin_exists ( wchar_t * cmd )
{
/*
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 ;
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 | |
wcscmp ( cmd , L " switch " ) = = 0 )
return 1 ;
return 0 ;
}
int builtin_run ( wchar_t * * argv )
{
int ( * cmd ) ( wchar_t * * argv ) = 0 ;
cmd = hash_get ( & builtin , argv [ 0 ] ) ;
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 ;
}
}
if ( cmd ! = 0 )
{
int status ;
status = cmd ( argv ) ;
// fwprintf( stderr, L"Builtin: Set status of %ls to %d\n", argv[0], status );
return status ;
}
else
{
2006-01-04 12:51:02 +00:00
debug ( 0 , _ ( L " Unknown builtin '%ls' " ) , argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
}
return 1 ;
}
void builtin_get_names ( array_list_t * list )
{
hash_get_keys ( & builtin , list ) ;
}
const wchar_t * builtin_get_desc ( const wchar_t * b )
{
if ( ! desc )
{
desc = malloc ( sizeof ( hash_table_t ) ) ;
if ( ! desc )
return 0 ;
hash_init ( desc , & hash_wcs_func , & hash_wcs_cmp ) ;
2006-01-08 02:56:56 +00:00
hash_put ( desc , L " block " , N_ ( L " Temporarily block delivery of events " ) ) ;
2006-01-11 14:17:35 +00:00
hash_put ( desc , L " builtin " , N_ ( L " Run a builtin command instead of a function " ) ) ;
2006-01-08 02:56:56 +00:00
hash_put ( desc , L " complete " , N_ ( L " Edit command specific completions " ) ) ;
hash_put ( desc , L " cd " , N_ ( L " Change working directory " ) ) ;
hash_put ( desc , L " exit " , N_ ( L " Exit the shell " ) ) ;
hash_put ( desc , L " function " , N_ ( L " Define a new function " ) ) ;
hash_put ( desc , L " functions " , N_ ( L " List or remove functions " ) ) ;
hash_put ( desc , L " end " , N_ ( L " End a block of commands " ) ) ;
hash_put ( desc , L " else " , N_ ( L " Evaluate block if condition is false " ) ) ;
hash_put ( desc , L " eval " , N_ ( L " Evaluate parameters as a command " ) ) ;
hash_put ( desc , L " for " , N_ ( L " Perform a set of commands multiple times " ) ) ;
hash_put ( desc , L " . " , N_ ( L " Evaluate contents of file " ) ) ;
hash_put ( desc , L " set " , N_ ( L " Handle environment variables " ) ) ;
hash_put ( desc , L " fg " , N_ ( L " Send job to foreground " ) ) ;
hash_put ( desc , L " bg " , N_ ( L " Send job to background " ) ) ;
hash_put ( desc , L " jobs " , N_ ( L " Print currently running jobs " ) ) ;
hash_put ( desc , L " read " , N_ ( L " Read a line of input into variables " ) ) ;
hash_put ( desc , L " break " , N_ ( L " Stop the innermost loop " ) ) ;
hash_put ( desc , L " continue " , N_ ( L " Skip the rest of the current lap of the innermost loop " ) ) ;
2006-01-11 14:17:35 +00:00
hash_put ( desc , L " return " , N_ ( L " Stop the currently evaluated function " ) ) ;
2006-01-08 02:56:56 +00:00
hash_put ( desc , L " commandline " , N_ ( L " Set or get the commandline " ) ) ;
hash_put ( desc , L " switch " , N_ ( L " Conditionally execute a block of commands " ) ) ;
hash_put ( desc , L " case " , N_ ( L " Conditionally execute a block of commands " ) ) ;
2006-01-11 14:17:35 +00:00
hash_put ( desc , L " command " , N_ ( L " Run a program instead of a function or builtin " ) ) ;
hash_put ( desc , L " if " , N_ ( L " Evaluate block if condition is true " ) ) ;
2006-01-08 02:56:56 +00:00
hash_put ( desc , L " while " , N_ ( L " Perform a command multiple times " ) ) ;
2006-01-11 14:17:35 +00:00
hash_put ( desc , L " bind " , N_ ( L " Handle fish key bindings " ) ) ;
2006-01-08 02:56:56 +00:00
hash_put ( desc , L " random " , N_ ( L " Generate random number " ) ) ;
hash_put ( desc , L " exec " , N_ ( L " Run command in current process " ) ) ;
hash_put ( desc , L " not " , N_ ( L " Negate exit status of job " ) ) ;
2006-01-11 14:17:35 +00:00
hash_put ( desc , L " or " , N_ ( L " Execute command if previous command failed " ) ) ;
hash_put ( desc , L " and " , N_ ( L " Execute command if previous command suceeded " ) ) ;
2006-01-08 02:56:56 +00:00
hash_put ( desc , L " begin " , N_ ( L " Create a block of code " ) ) ;
hash_put ( desc , L " status " , N_ ( L " Return status information about fish " ) ) ;
hash_put ( desc , L " ulimit " , N_ ( L " Set or get the shells resource usage limits " ) ) ;
}
return _ ( hash_get ( desc , b ) ) ;
2005-09-20 13:26:39 +00:00
}
void builtin_push_io ( int in )
{
if ( builtin_stdin ! = - 1 )
{
al_push ( & io_stack , ( void * ) ( long ) builtin_stdin ) ;
al_push ( & io_stack , sb_out ) ;
al_push ( & io_stack , sb_err ) ;
}
builtin_stdin = in ;
sb_out = malloc ( sizeof ( string_buffer_t ) ) ;
sb_err = malloc ( sizeof ( string_buffer_t ) ) ;
sb_init ( sb_out ) ;
sb_init ( sb_err ) ;
}
void builtin_pop_io ( )
{
builtin_stdin = 0 ;
sb_destroy ( sb_out ) ;
sb_destroy ( sb_err ) ;
free ( sb_out ) ;
free ( sb_err ) ;
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 ) ;
builtin_stdin = ( int ) ( long ) al_pop ( & io_stack ) ;
}
else
{
sb_out = sb_err = 0 ;
builtin_stdin = 0 ;
}
}