diff --git a/builtin.cpp b/builtin.cpp
index 707d0cd80..7e7a87dc4 100644
--- a/builtin.cpp
+++ b/builtin.cpp
@@ -1,19 +1,19 @@
/** \file builtin.c
- Functions for executing builtin functions.
+ Functions for executing builtin functions.
- How to add a new builtin function:
+ How to add a new builtin function:
- 1). Create a function in builtin.c with the following signature:
+ 1). Create a function in builtin.c with the following signature:
- static int builtin_NAME( parser_t &parser, wchar_t ** args )
+ static int builtin_NAME( parser_t &parser, wchar_t ** args )
- where NAME is the name of the builtin, and args is a zero-terminated list of arguments.
+ where NAME is the name of the builtin, and args is a zero-terminated list of arguments.
- 2). Add a line like { L"NAME", &builtin_NAME, N_(L"Bla bla bla") }, to the builtin_data_t variable. The description is used by the completion system. Note that this array is sorted!
+ 2). Add a line like { L"NAME", &builtin_NAME, N_(L"Bla bla bla") }, to the builtin_data_t variable. The description is used by the completion system. Note that this array is sorted!
- 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.
+ 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.
- 4). Use 'darcs add doc_src/NAME.txt' to start tracking changes to the documentation file.
+ 4). Use 'darcs add doc_src/NAME.txt' to start tracking changes to the documentation file.
*/
@@ -82,23 +82,23 @@
#define FG_MSG _( L"Send job %d, '%ls' to foreground\n" )
/**
- Datastructure to describe a builtin.
+ Datastructure to describe a builtin.
*/
struct builtin_data_t
{
- /**
- Name of the builtin
- */
- const wchar_t *name;
- /**
- Function pointer tothe builtin implementation
- */
- int (*func)(parser_t &parser, wchar_t **argv);
- /**
- Description of what the builtin does
- */
- const wchar_t *desc;
-
+ /**
+ Name of the builtin
+ */
+ const wchar_t *name;
+ /**
+ Function pointer tothe builtin implementation
+ */
+ int (*func)(parser_t &parser, wchar_t **argv);
+ /**
+ Description of what the builtin does
+ */
+ const wchar_t *desc;
+
bool operator<(const wcstring &) const;
bool operator<(const builtin_data_t *) const;
};
@@ -162,35 +162,35 @@ static const io_chain_t *real_io;
*/
static int builtin_count_args( wchar_t **argv )
{
- int argc = 1;
- while( argv[argc] != 0 )
- {
- argc++;
- }
- return argc;
+ int argc = 1;
+ while( argv[argc] != 0 )
+ {
+ argc++;
+ }
+ return argc;
}
-/**
- This function works like wperror, but it prints its result into
- the sb_err string instead of to stderr. Used by the builtin
- commands.
+/**
+ This function works like wperror, but it prints its result into
+ the sb_err string instead of to stderr. Used by the builtin
+ commands.
*/
static void builtin_wperror( const wchar_t *s)
{
- if( s != 0 )
- {
+ if( s != 0 )
+ {
stderr_buffer.append(s);
stderr_buffer.append(L": ");
- }
- char *err = strerror( errno );
- wchar_t *werr = str2wcs( err );
- if( werr )
- {
+ }
+ char *err = strerror( errno );
+ wchar_t *werr = str2wcs( err );
+ if( werr )
+ {
stderr_buffer.append(werr);
stderr_buffer.push_back(L'\n');
- free( werr );
- }
+ free( werr );
+ }
}
/**
@@ -198,12 +198,12 @@ static void builtin_wperror( const wchar_t *s)
*/
static int count_char( const wchar_t *str, wchar_t c )
{
- int res = 0;
- for( ; *str; str++ )
- {
- res += (*str==c);
- }
- return res;
+ int res = 0;
+ for( ; *str; str++ )
+ {
+ res += (*str==c);
+ }
+ return res;
}
wcstring builtin_help_get( parser_t &parser, const wchar_t *name )
@@ -212,15 +212,15 @@ wcstring builtin_help_get( parser_t &parser, const wchar_t *name )
wcstring out;
const wcstring name_esc = escape_string(name, 1);
const wcstring cmd = format_string(L"__fish_print_help %ls", name_esc.c_str());
- if( exec_subshell( cmd, lst ) >= 0 )
- {
- for( size_t i=0; i= 0 )
+ {
+ for( size_t i=0; i 2*screen_height/3) )
- {
- wchar_t *pos;
- int cut=0;
- int i;
-
- is_short = 1;
-
- /*
- First move down 4 lines
- */
-
- pos = str;
- for( i=0; (i<4) && pos && *pos; i++ )
- {
- pos = wcschr( pos+1, L'\n' );
- }
-
- if( pos && *pos )
- {
-
- /*
- Then find the next empty line
- */
- for( ; *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 )
- {
- /*
- And cut it
- */
- *(pos2+1)=L'\0';
- cut = 1;
- break;
- }
- }
- }
- }
-
- /*
- We did not find a good place to cut message to
- shorten it - so we make sure we don't print
- anything.
- */
- if( !cut )
- {
- *str = 0;
- }
-
- }
- }
+ screen_height = common_get_height();
+ lines = count_char( str, L'\n' );
+ if( !get_is_interactive() || (lines > 2*screen_height/3) )
+ {
+ wchar_t *pos;
+ int cut=0;
+ int i;
+
+ is_short = 1;
+
+ /*
+ First move down 4 lines
+ */
+
+ pos = str;
+ for( i=0; (i<4) && pos && *pos; i++ )
+ {
+ pos = wcschr( pos+1, L'\n' );
+ }
+
+ if( pos && *pos )
+ {
+
+ /*
+ Then find the next empty line
+ */
+ for( ; *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 )
+ {
+ /*
+ And cut it
+ */
+ *(pos2+1)=L'\0';
+ cut = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ We did not find a good place to cut message to
+ shorten it - so we make sure we don't print
+ anything.
+ */
+ if( !cut )
+ {
+ *str = 0;
+ }
+ }
+ }
+
b.append(str);
- if( is_short )
- {
+ if( is_short )
+ {
append_format(b, _(L"%ls: Type 'help %ls' for related documentation\n\n"), cmd, cmd);
- }
-
- free( str );
- }
+ }
+
+ free( str );
+ }
}
/**
@@ -349,7 +349,7 @@ static void builtin_print_help( parser_t &parser, const wchar_t *cmd, wcstring &
static void builtin_unknown_option( parser_t &parser, const wchar_t *cmd, const wchar_t *opt )
{
append_format(stderr_buffer, BUILTIN_ERR_UNKNOWN, cmd, opt);
- builtin_print_help( parser, cmd, stderr_buffer );
+ builtin_print_help( parser, cmd, stderr_buffer );
}
/**
@@ -358,7 +358,7 @@ static void builtin_unknown_option( parser_t &parser, const wchar_t *cmd, const
static void builtin_missing_argument( parser_t &parser, const wchar_t *cmd, const wchar_t *opt )
{
append_format(stderr_buffer, BUILTIN_ERR_MISSING, cmd, opt);
- builtin_print_help( parser, cmd, stderr_buffer );
+ builtin_print_help( parser, cmd, stderr_buffer );
}
/*
@@ -396,29 +396,29 @@ int builtin_test( parser_t &parser, wchar_t **argv );
*/
static void builtin_bind_list()
{
- size_t i;
+ size_t i;
wcstring_list_t lst;
- input_mapping_get_names( lst );
-
- for( i=0; iouter )
- block=0;
- break;
- }
- case GLOBAL:
- {
- block=0;
- }
- case UNSET:
- {
- while( block &&
- block->type() != FUNCTION_CALL &&
- block->type() != FUNCTION_CALL_NO_SHADOW )
- block = block->outer;
- }
- }
- if( block )
- {
+ switch( scope )
+ {
+ case LOCAL:
+ {
+ if( !block->outer )
+ block=0;
+ break;
+ }
+ case GLOBAL:
+ {
+ block=0;
+ }
+ case UNSET:
+ {
+ while( block &&
+ block->type() != FUNCTION_CALL &&
+ block->type() != FUNCTION_CALL_NO_SHADOW )
+ block = block->outer;
+ }
+ }
+ if( block )
+ {
block->event_blocks.push_front(eb);
- }
- else
- {
+ }
+ else
+ {
parser.global_event_blocks.push_front(eb);
- }
- }
+ }
+ }
- return STATUS_BUILTIN_OK;
+ return STATUS_BUILTIN_OK;
}
@@ -869,83 +869,83 @@ static int builtin_block( parser_t &parser, wchar_t **argv )
*/
static int builtin_builtin( parser_t &parser, wchar_t **argv )
{
- int argc=builtin_count_args( argv );
- int list=0;
+ int argc=builtin_count_args( argv );
+ int list=0;
- woptind=0;
+ woptind=0;
- static const struct woption
- long_options[] =
- {
- {
- L"names", no_argument, 0, 'n'
- }
- ,
- {
- L"help", no_argument, 0, 'h'
- }
- ,
- {
- 0, 0, 0, 0
- }
- }
- ;
+ static const 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;
+ while( 1 )
+ {
+ int opt_index = 0;
- int opt = wgetopt_long( argc,
- argv,
- L"nh",
- long_options,
- &opt_index );
- if( opt == -1 )
- break;
+ 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;
+ switch( opt )
+ {
+ case 0:
+ if(long_options[opt_index].flag != 0)
+ break;
append_format(stderr_buffer,
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name );
- builtin_print_help( parser, argv[0], stderr_buffer );
+ builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- case 'h':
- builtin_print_help( parser, argv[0], stdout_buffer );
- return STATUS_BUILTIN_OK;
+ return STATUS_BUILTIN_ERROR;
+ case 'h':
+ builtin_print_help( parser, argv[0], stdout_buffer );
+ return STATUS_BUILTIN_OK;
- case 'n':
- list=1;
- break;
+ case 'n':
+ list=1;
+ break;
- case '?':
- builtin_unknown_option( parser, argv[0], argv[woptind-1] );
- return STATUS_BUILTIN_ERROR;
+ case '?':
+ builtin_unknown_option( parser, argv[0], argv[woptind-1] );
+ return STATUS_BUILTIN_ERROR;
- }
+ }
- }
+ }
- if( list )
- {
+ if( list )
+ {
wcstring_list_t names = builtin_get_names();
sort(names.begin(), names.end());
-
- for( size_t i=0; i ev;
- event_get( &search, &ev );
+ std::vector ev;
+ event_get( &search, &ev );
out.append(L"function ");
-
+
/* Typically we prefer to specify the function name first, e.g. "function foo --description bar"
But If the function name starts with a -, we'll need to output it after all the options. */
bool defer_function_name = (name.at(0) == L'-');
@@ -1107,82 +1107,82 @@ static void functions_def( const wcstring &name, wcstring &out )
out.append(name);
}
- if (! desc.empty())
- {
+ if (! desc.empty())
+ {
wcstring esc_desc = escape_string(desc, true);
- out.append(L" --description ");
+ out.append(L" --description ");
out.append(esc_desc);
- }
+ }
- if( !function_get_shadows( name ) )
- {
- out.append(L" --no-scope-shadowing" );
- }
+ if( !function_get_shadows( name ) )
+ {
+ out.append(L" --no-scope-shadowing" );
+ }
- for( size_t i=0; itype )
- {
- case EVENT_SIGNAL:
- {
- append_format( out, L" --on-signal %ls", sig2wcs( next->param1.signal ) );
- break;
- }
+ for( size_t i=0; itype )
+ {
+ case EVENT_SIGNAL:
+ {
+ append_format( out, L" --on-signal %ls", sig2wcs( next->param1.signal ) );
+ break;
+ }
- case EVENT_VARIABLE:
- {
- append_format( out, L" --on-variable %ls", next->str_param1.c_str() );
- break;
- }
+ case EVENT_VARIABLE:
+ {
+ append_format( out, L" --on-variable %ls", next->str_param1.c_str() );
+ break;
+ }
- case EVENT_EXIT:
- {
- if( next->param1.pid > 0 )
- append_format( out, L" --on-process-exit %d", next->param1.pid );
- else
- append_format( out, L" --on-job-exit %d", -next->param1.pid );
- break;
- }
+ case EVENT_EXIT:
+ {
+ if( next->param1.pid > 0 )
+ append_format( out, L" --on-process-exit %d", next->param1.pid );
+ else
+ append_format( out, L" --on-job-exit %d", -next->param1.pid );
+ break;
+ }
- case EVENT_JOB_ID:
- {
- const job_t *j = job_get( next->param1.job_id );
- if( j )
- append_format( out, L" --on-job-exit %d", j->pgid );
- break;
- }
+ case EVENT_JOB_ID:
+ {
+ const job_t *j = job_get( next->param1.job_id );
+ if( j )
+ append_format( out, L" --on-job-exit %d", j->pgid );
+ break;
+ }
- case EVENT_GENERIC:
- {
- append_format( out, L" --on-event %ls", next->str_param1.c_str() );
- break;
- }
-
- }
-
- }
+ case EVENT_GENERIC:
+ {
+ append_format( out, L" --on-event %ls", next->str_param1.c_str() );
+ break;
+ }
+
+ }
+ }
+
wcstring_list_t named = function_get_named_arguments( name );
- if( named.size() > 0 )
- {
- append_format( out, L" --argument" );
- for( size_t i=0; i < named.size(); i++ )
- {
- append_format( out, L" %ls", named.at(i).c_str() );
- }
- }
+ if( named.size() > 0 )
+ {
+ append_format( out, L" --argument" );
+ for( size_t i=0; i < named.size(); i++ )
+ {
+ append_format( out, L" %ls", named.at(i).c_str() );
+ }
+ }
/* Output the function name if we deferred it */
if ( defer_function_name ){
out.append(L" -- ");
out.append(name);
}
-
+
/* This forced tab is sort of crummy - not all functions start with a tab */
append_format( out, L"\n\t%ls", def.c_str());
-
+
/* Append a newline before the 'end', unless there already is one there */
if (! string_suffixes_string(L"\n", def)) {
out.push_back(L'\n');
@@ -1196,271 +1196,271 @@ static void functions_def( const wcstring &name, wcstring &out )
*/
static int builtin_functions( parser_t &parser, wchar_t **argv )
{
- int i;
- int erase=0;
- wchar_t *desc=0;
+ int i;
+ int erase=0;
+ wchar_t *desc=0;
- int argc=builtin_count_args( argv );
- int list=0;
- int show_hidden=0;
- int res = STATUS_BUILTIN_OK;
- int query = 0;
- int copy = 0;
+ int argc=builtin_count_args( argv );
+ int list=0;
+ int show_hidden=0;
+ int res = STATUS_BUILTIN_OK;
+ int query = 0;
+ int copy = 0;
- woptind=0;
+ woptind=0;
- static const 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'
- }
- ,
- {
- L"help", no_argument, 0, 'h'
- }
- ,
- {
- L"query", no_argument, 0, 'q'
- }
- ,
- {
- L"copy", no_argument, 0, 'c'
- }
- ,
- {
- 0, 0, 0, 0
- }
- }
- ;
+ static const 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'
+ }
+ ,
+ {
+ L"help", no_argument, 0, 'h'
+ }
+ ,
+ {
+ L"query", no_argument, 0, 'q'
+ }
+ ,
+ {
+ L"copy", no_argument, 0, 'c'
+ }
+ ,
+ {
+ 0, 0, 0, 0
+ }
+ }
+ ;
- while( 1 )
- {
- int opt_index = 0;
+ while( 1 )
+ {
+ int opt_index = 0;
- int opt = wgetopt_long( argc,
- argv,
- L"ed:nahqc",
- long_options,
- &opt_index );
- if( opt == -1 )
- break;
+ int opt = wgetopt_long( argc,
+ argv,
+ L"ed:nahqc",
+ long_options,
+ &opt_index );
+ if( opt == -1 )
+ break;
- switch( opt )
- {
- case 0:
- if(long_options[opt_index].flag != 0)
- break;
+ switch( opt )
+ {
+ case 0:
+ if(long_options[opt_index].flag != 0)
+ break;
append_format(stderr_buffer,
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name );
- builtin_print_help( parser, argv[0], stderr_buffer );
+ builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
+ return STATUS_BUILTIN_ERROR;
- case 'e':
- erase=1;
- break;
+ case 'e':
+ erase=1;
+ break;
- case 'd':
- desc=woptarg;
- break;
+ case 'd':
+ desc=woptarg;
+ break;
- case 'n':
- list=1;
- break;
+ case 'n':
+ list=1;
+ break;
- case 'a':
- show_hidden=1;
- break;
+ case 'a':
+ show_hidden=1;
+ break;
- case 'h':
- builtin_print_help( parser, argv[0], stdout_buffer );
- return STATUS_BUILTIN_OK;
+ case 'h':
+ builtin_print_help( parser, argv[0], stdout_buffer );
+ return STATUS_BUILTIN_OK;
- case 'q':
- query = 1;
- break;
+ case 'q':
+ query = 1;
+ break;
- case 'c':
- copy = 1;
- break;
+ case 'c':
+ copy = 1;
+ break;
- case '?':
- builtin_unknown_option( parser, argv[0], argv[woptind-1] );
- return STATUS_BUILTIN_ERROR;
+ case '?':
+ builtin_unknown_option( parser, argv[0], argv[woptind-1] );
+ return STATUS_BUILTIN_ERROR;
- }
+ }
- }
+ }
- /*
- Erase, desc, query, copy and list are mutually exclusive
- */
- if( (erase + (!!desc) + list + query + copy) > 1 )
- {
- append_format(stderr_buffer,
- _( L"%ls: Invalid combination of options\n" ),
- argv[0] );
+ /*
+ Erase, desc, query, copy and list are mutually exclusive
+ */
+ if( (erase + (!!desc) + list + query + copy) > 1 )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Invalid combination of options\n" ),
+ argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
+ builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
+ return STATUS_BUILTIN_ERROR;
+ }
- if( erase )
- {
- int i;
- for( i=woptind; i start)
{
@@ -1558,7 +1558,7 @@ static int builtin_echo( parser_t &parser, wchar_t **argv )
/* Skip first arg */
if (! *argv++)
return STATUS_BUILTIN_ERROR;
-
+
/* Process options */
bool print_newline = true, print_spaces = true, interpret_special_chars = false;
while (*argv) {
@@ -1575,10 +1575,10 @@ static int builtin_echo( parser_t &parser, wchar_t **argv )
}
argv++;
}
-
+
/* The special character \c can be used to indicate no more output */
bool continue_output = true;
-
+
for (size_t idx = 0; continue_output && argv[idx] != NULL; idx++) {
if (print_spaces && idx > 0)
@@ -1608,9 +1608,9 @@ static int builtin_echo( parser_t &parser, wchar_t **argv )
case L't': wc = L'\t'; break;
case L'v': wc = L'\v'; break;
case L'\\': wc = L'\\'; break;
-
+
case L'c': wc = 0; continue_output = false; break;
-
+
default:
{
/* Octal and hex escape sequences */
@@ -1629,10 +1629,10 @@ static int builtin_echo( parser_t &parser, wchar_t **argv )
break;
}
}
-
+
/* Skip over characters that were part of this escape sequence (but not the backslash, which will be handled by the loop increment */
j += consumed;
-
+
if (continue_output)
stdout_buffer.push_back(wc);
}
@@ -1646,8 +1646,8 @@ static int builtin_echo( parser_t &parser, wchar_t **argv )
/** The pwd builtin. We don't respect -P to resolve symbolic links because we try to always resolve them. */
static int builtin_pwd( parser_t &parser, wchar_t **argv )
{
- wchar_t dir_path[4096];
- wchar_t *res = wgetcwd( dir_path, 4096 );
+ wchar_t dir_path[4096];
+ wchar_t *res = wgetcwd( dir_path, 4096 );
if (res == NULL) {
return STATUS_BUILTIN_ERROR;
} else {
@@ -1663,348 +1663,348 @@ static int builtin_pwd( parser_t &parser, wchar_t **argv )
*/
static int builtin_function( parser_t &parser, wchar_t **argv )
{
- int argc = builtin_count_args( argv );
- int res=STATUS_BUILTIN_OK;
- wchar_t *desc=0;
- std::vector events;
-
+ int argc = builtin_count_args( argv );
+ int res=STATUS_BUILTIN_OK;
+ wchar_t *desc=0;
+ std::vector events;
+
std::auto_ptr named_arguments(NULL);
- wchar_t *name = 0;
- bool shadows = true;
-
- woptind=0;
+ wchar_t *name = 0;
+ bool shadows = true;
+
+ woptind=0;
function_def_block_t * const fdb = new function_def_block_t();
- parser.push_block( fdb );
+ parser.push_block( fdb );
- static const struct woption
- long_options[] =
- {
- {
- L"description", required_argument, 0, 'd'
- }
- ,
- {
- L"on-signal", required_argument, 0, 's'
- }
- ,
- {
- L"on-job-exit", required_argument, 0, 'j'
- }
- ,
- {
- L"on-process-exit", required_argument, 0, 'p'
- }
- ,
- {
- L"on-variable", required_argument, 0, 'v'
- }
- ,
- {
- L"on-event", required_argument, 0, 'e'
- }
- ,
- {
- L"help", no_argument, 0, 'h'
- }
- ,
- {
- L"argument-names", no_argument, 0, 'a'
- }
- ,
- {
- L"no-scope-shadowing", no_argument, 0, 'S'
- }
- ,
- {
- 0, 0, 0, 0
- }
- }
- ;
+ static const struct woption
+ long_options[] =
+ {
+ {
+ L"description", required_argument, 0, 'd'
+ }
+ ,
+ {
+ L"on-signal", required_argument, 0, 's'
+ }
+ ,
+ {
+ L"on-job-exit", required_argument, 0, 'j'
+ }
+ ,
+ {
+ L"on-process-exit", required_argument, 0, 'p'
+ }
+ ,
+ {
+ L"on-variable", required_argument, 0, 'v'
+ }
+ ,
+ {
+ L"on-event", required_argument, 0, 'e'
+ }
+ ,
+ {
+ L"help", no_argument, 0, 'h'
+ }
+ ,
+ {
+ L"argument-names", no_argument, 0, 'a'
+ }
+ ,
+ {
+ L"no-scope-shadowing", no_argument, 0, 'S'
+ }
+ ,
+ {
+ 0, 0, 0, 0
+ }
+ }
+ ;
- while( 1 && (!res ) )
- {
- int opt_index = 0;
+ while( 1 && (!res ) )
+ {
+ int opt_index = 0;
- int opt = wgetopt_long( argc,
- argv,
- L"d:s:j:p:v:e:haS",
- long_options,
- &opt_index );
- if( opt == -1 )
- break;
+ int opt = wgetopt_long( argc,
+ argv,
+ L"d:s:j:p:v:e:haS",
+ long_options,
+ &opt_index );
+ if( opt == -1 )
+ break;
- switch( opt )
- {
- case 0:
- if(long_options[opt_index].flag != 0)
- break;
+ switch( opt )
+ {
+ case 0:
+ if(long_options[opt_index].flag != 0)
+ break;
append_format(stderr_buffer,
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name );
- res = 1;
- break;
+ res = 1;
+ break;
- case 'd':
- desc=woptarg;
- break;
+ case 'd':
+ desc=woptarg;
+ break;
- case 's':
- {
- int sig = wcs2sig( woptarg );
+ case 's':
+ {
+ int sig = wcs2sig( woptarg );
- if( sig < 0 )
- {
- append_format(stderr_buffer,
- _( L"%ls: Unknown signal '%ls'\n" ),
- argv[0],
- woptarg );
- res=1;
- break;
- }
+ if( sig < 0 )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Unknown signal '%ls'\n" ),
+ argv[0],
+ woptarg );
+ res=1;
+ break;
+ }
events.push_back(event_t::signal_event(sig));
- break;
- }
+ break;
+ }
- case 'v':
- {
- if( wcsvarname( woptarg ) )
- {
- append_format(stderr_buffer,
- _( L"%ls: Invalid variable name '%ls'\n" ),
- argv[0],
- woptarg );
- res=STATUS_BUILTIN_ERROR;
- break;
- }
+ case 'v':
+ {
+ if( wcsvarname( woptarg ) )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Invalid variable name '%ls'\n" ),
+ argv[0],
+ woptarg );
+ res=STATUS_BUILTIN_ERROR;
+ break;
+ }
events.push_back(event_t::variable_event(woptarg));
- break;
- }
+ break;
+ }
- case 'e':
- {
+ case 'e':
+ {
events.push_back(event_t::generic_event(woptarg));
- break;
- }
+ break;
+ }
- case 'j':
- case 'p':
- {
- pid_t pid;
- wchar_t *end;
+ case 'j':
+ case 'p':
+ {
+ pid_t pid;
+ wchar_t *end;
event_t e(EVENT_ANY);
+
+ if( ( opt == 'j' ) &&
+ ( wcscasecmp( woptarg, L"caller" ) == 0 ) )
+ {
+ int job_id = -1;
- if( ( opt == 'j' ) &&
- ( wcscasecmp( woptarg, L"caller" ) == 0 ) )
- {
- int job_id = -1;
+ if( is_subshell )
+ {
+ block_t *b = parser.current_block;
- if( is_subshell )
- {
- block_t *b = parser.current_block;
+ while( b && (b->type() != SUBST) )
+ b = b->outer;
- while( b && (b->type() != SUBST) )
- b = b->outer;
+ if( b )
+ {
+ b=b->outer;
+ }
+ if( b->job )
+ {
+ job_id = b->job->job_id;
+ }
+ }
- if( b )
- {
- b=b->outer;
- }
- if( b->job )
- {
- job_id = b->job->job_id;
- }
- }
+ if( job_id == -1 )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Cannot find calling job for event handler\n" ),
+ argv[0] );
+ res=1;
+ }
+ else
+ {
+ e.type = EVENT_JOB_ID;
+ e.param1.job_id = job_id;
+ }
- if( job_id == -1 )
- {
- append_format(stderr_buffer,
- _( L"%ls: Cannot find calling job for event handler\n" ),
- argv[0] );
- res=1;
- }
- else
- {
- e.type = EVENT_JOB_ID;
- e.param1.job_id = job_id;
- }
-
- }
- else
- {
- errno = 0;
- pid = fish_wcstoi( woptarg, &end, 10 );
- if( errno || !end || *end )
- {
- append_format(stderr_buffer,
- _( L"%ls: Invalid process id %ls\n" ),
- argv[0],
- woptarg );
- res=1;
- break;
- }
+ }
+ else
+ {
+ errno = 0;
+ pid = fish_wcstoi( woptarg, &end, 10 );
+ if( errno || !end || *end )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Invalid process id %ls\n" ),
+ argv[0],
+ woptarg );
+ res=1;
+ break;
+ }
- e.type = EVENT_EXIT;
- e.param1.pid = (opt=='j'?-1:1)*abs(pid);
- }
- if( res )
- {
+ e.type = EVENT_EXIT;
+ e.param1.pid = (opt=='j'?-1:1)*abs(pid);
+ }
+ if( res )
+ {
/* nothing */
- }
- else
- {
+ }
+ else
+ {
events.push_back(e);
- }
- break;
- }
+ }
+ break;
+ }
- case 'a':
- if( named_arguments.get() == NULL )
- named_arguments.reset(new wcstring_list_t);
- break;
+ case 'a':
+ if( named_arguments.get() == NULL )
+ named_arguments.reset(new wcstring_list_t);
+ break;
+
+ case 'S':
+ shadows = 0;
+ break;
+
+ case 'h':
+ parser.pop_block();
+ parser.push_block( new fake_block_t() );
+ builtin_print_help( parser, argv[0], stdout_buffer );
+ return STATUS_BUILTIN_OK;
+
+ case '?':
+ builtin_unknown_option( parser, argv[0], argv[woptind-1] );
+ res = 1;
+ break;
- case 'S':
- shadows = 0;
- break;
+ }
- case 'h':
- parser.pop_block();
- parser.push_block( new fake_block_t() );
- builtin_print_help( parser, argv[0], stdout_buffer );
- return STATUS_BUILTIN_OK;
+ }
- case '?':
- builtin_unknown_option( parser, argv[0], argv[woptind-1] );
- res = 1;
- break;
+ if( !res )
+ {
+
+ if( argc == woptind )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Expected function name\n" ),
+ argv[0] );
+ res=1;
+ }
+ else if( wcsfuncname( argv[woptind] ) )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Illegal function name '%ls'\n" ),
+ argv[0],
+ argv[woptind] );
- }
+ res=1;
+ }
+ else if( parser_keywords_is_reserved(argv[woptind] ) )
+ {
- }
+ append_format(stderr_buffer,
+ _( L"%ls: The name '%ls' is reserved,\nand can not be used as a function name\n" ),
+ argv[0],
+ argv[woptind] );
- if( !res )
- {
-
- if( argc == woptind )
- {
- append_format(stderr_buffer,
- _( L"%ls: Expected function name\n" ),
- argv[0] );
- res=1;
- }
- else if( wcsfuncname( argv[woptind] ) )
- {
- append_format(stderr_buffer,
- _( L"%ls: Illegal function name '%ls'\n" ),
- argv[0],
- argv[woptind] );
-
- res=1;
- }
- else if( parser_keywords_is_reserved(argv[woptind] ) )
- {
-
- append_format(stderr_buffer,
- _( L"%ls: The name '%ls' is reserved,\nand can not be used as a function name\n" ),
- argv[0],
- argv[woptind] );
-
- res=1;
- }
- else
- {
-
- name = argv[woptind++];
-
- if( named_arguments.get() )
- {
- while( woptind < argc )
- {
- if( wcsvarname( argv[woptind] ) )
- {
- append_format(stderr_buffer,
- _( L"%ls: Invalid variable name '%ls'\n" ),
- argv[0],
- argv[woptind] );
- res = STATUS_BUILTIN_ERROR;
- break;
- }
+ res=1;
+ }
+ else
+ {
+ name = argv[woptind++];
+
+ if( named_arguments.get() )
+ {
+ while( woptind < argc )
+ {
+ if( wcsvarname( argv[woptind] ) )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Invalid variable name '%ls'\n" ),
+ argv[0],
+ argv[woptind] );
+ res = STATUS_BUILTIN_ERROR;
+ break;
+ }
+
named_arguments->push_back(argv[woptind++]);
- }
- }
- else if( woptind != argc )
- {
- append_format(stderr_buffer,
- _( L"%ls: Expected one argument, got %d\n" ),
- argv[0],
- argc );
- res=1;
+ }
+ }
+ else if( woptind != argc )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Expected one argument, got %d\n" ),
+ argv[0],
+ argc );
+ res=1;
+
+ }
+ }
+ }
- }
- }
- }
+ if( res )
+ {
+ size_t i;
+ size_t chars=0;
- if( res )
- {
- size_t i;
- size_t chars=0;
-
- builtin_print_help( parser, argv[0], stderr_buffer );
- const wchar_t *cfa = _( L"Current functions are: " );
- stderr_buffer.append( cfa );
- chars += wcslen( cfa );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ const wchar_t *cfa = _( L"Current functions are: " );
+ stderr_buffer.append( cfa );
+ chars += wcslen( cfa );
wcstring_list_t names = function_get_names(0);
sort(names.begin(), names.end());
- for( i=0; i common_get_width() )
- {
- chars = 0;
+ for( i=0; i common_get_width() )
+ {
+ chars = 0;
stderr_buffer.push_back(L'\n');
- }
+ }
stderr_buffer.append(nxt);
stderr_buffer.append(L" ");
- }
+ }
stderr_buffer.push_back(L'\n');
- parser.pop_block();
- parser.push_block( new fake_block_t() );
- }
- else
- {
- function_data_t &d = fdb->function_data;
-
+ parser.pop_block();
+ parser.push_block( new fake_block_t() );
+ }
+ else
+ {
+ function_data_t &d = fdb->function_data;
+
d.name = name;
if (desc)
d.description = desc;
- d.events.swap(events);
- d.shadows = shadows;
+ d.events.swap(events);
+ d.shadows = shadows;
if (named_arguments.get())
d.named_arguments.swap(*named_arguments);
+
+ for( size_t i=0; itok_pos = parser.get_pos();
+ parser.current_block->skip = 1;
- for( size_t i=0; itok_pos = parser.get_pos();
- parser.current_block->skip = 1;
-
- return STATUS_BUILTIN_OK;
+ return STATUS_BUILTIN_OK;
}
@@ -2013,113 +2013,113 @@ static int builtin_function( parser_t &parser, wchar_t **argv )
*/
static int builtin_random( parser_t &parser, wchar_t **argv )
{
- static int seeded=0;
- static struct drand48_data seed_buffer;
+ static int seeded=0;
+ static struct drand48_data seed_buffer;
+
+ int argc = builtin_count_args( argv );
- int argc = builtin_count_args( argv );
+ woptind=0;
- woptind=0;
+ static const struct woption
+ long_options[] =
+ {
+ {
+ L"help", no_argument, 0, 'h'
+ }
+ ,
+ {
+ 0, 0, 0, 0
+ }
+ }
+ ;
- static const struct woption
- long_options[] =
- {
- {
- L"help", no_argument, 0, 'h'
- }
- ,
- {
- 0, 0, 0, 0
- }
- }
- ;
+ while( 1 )
+ {
+ int opt_index = 0;
- while( 1 )
- {
- int opt_index = 0;
+ int opt = wgetopt_long( argc,
+ argv,
+ L"h",
+ long_options,
+ &opt_index );
+ if( opt == -1 )
+ break;
- 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;
+ switch( opt )
+ {
+ case 0:
+ if(long_options[opt_index].flag != 0)
+ break;
append_format(stderr_buffer,
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name );
- builtin_print_help( parser, argv[0], stderr_buffer );
+ builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
+ return STATUS_BUILTIN_ERROR;
- case 'h':
- builtin_print_help( parser, argv[0], stdout_buffer );
- break;
+ case 'h':
+ builtin_print_help( parser, argv[0], stdout_buffer );
+ break;
- case '?':
- builtin_unknown_option( parser, argv[0], argv[woptind-1] );
- return STATUS_BUILTIN_ERROR;
+ case '?':
+ builtin_unknown_option( parser, argv[0], argv[woptind-1] );
+ return STATUS_BUILTIN_ERROR;
- }
+ }
- }
+ }
- switch( argc-woptind )
- {
+ switch( argc-woptind )
+ {
- case 0:
- {
- long res;
+ case 0:
+ {
+ long res;
+
+ if( !seeded )
+ {
+ seeded=1;
+ srand48_r(time(0), &seed_buffer);
+ }
+ lrand48_r( &seed_buffer, &res );
+
+ append_format(stdout_buffer, L"%ld\n", labs(res%32767) );
+ break;
+ }
- if( !seeded )
- {
- seeded=1;
- srand48_r(time(0), &seed_buffer);
- }
- lrand48_r( &seed_buffer, &res );
+ case 1:
+ {
+ long foo;
+ wchar_t *end=0;
- append_format(stdout_buffer, L"%ld\n", labs(res%32767) );
- break;
- }
+ errno=0;
+ foo = wcstol( argv[woptind], &end, 10 );
+ if( errno || *end )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Seed value '%ls' is not a valid number\n" ),
+ argv[0],
+ argv[woptind] );
- case 1:
- {
- long foo;
- wchar_t *end=0;
+ return STATUS_BUILTIN_ERROR;
+ }
+ seeded=1;
+ srand48_r( foo, &seed_buffer);
+ break;
+ }
- errno=0;
- foo = wcstol( argv[woptind], &end, 10 );
- if( errno || *end )
- {
- append_format(stderr_buffer,
- _( L"%ls: Seed value '%ls' is not a valid number\n" ),
- argv[0],
- argv[woptind] );
-
- return STATUS_BUILTIN_ERROR;
- }
- seeded=1;
- srand48_r( foo, &seed_buffer);
- break;
- }
-
- default:
- {
- append_format(stderr_buffer,
- _( L"%ls: Expected zero or one argument, got %d\n" ),
- argv[0],
- argc-woptind );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
- }
- return STATUS_BUILTIN_OK;
+ default:
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Expected zero or one argument, got %d\n" ),
+ argv[0],
+ argc-woptind );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
+ }
+ return STATUS_BUILTIN_OK;
}
@@ -2128,308 +2128,310 @@ static int builtin_random( parser_t &parser, wchar_t **argv )
*/
static int builtin_read( parser_t &parser, wchar_t **argv )
{
- wchar_t *buff=0;
- int i, argc = builtin_count_args( argv );
- int place = ENV_USER;
- wchar_t *nxt;
- const wchar_t *prompt = DEFAULT_READ_PROMPT;
- const wchar_t *commandline = L"";
- int exit_res=STATUS_BUILTIN_OK;
- const wchar_t *mode_name = READ_MODE_NAME;
- int shell = 0;
+ wchar_t *buff=0;
+ int i, argc = builtin_count_args( argv );
+ int place = ENV_USER;
+ wchar_t *nxt;
+ const wchar_t *prompt = DEFAULT_READ_PROMPT;
+ const wchar_t *commandline = L"";
+ int exit_res=STATUS_BUILTIN_OK;
+ const wchar_t *mode_name = READ_MODE_NAME;
+ int shell = 0;
+
+ woptind=0;
+
+ while( 1 )
+ {
+ static const struct woption
+ long_options[] =
+ {
+ {
+ L"export", no_argument, 0, 'x'
+ }
+ ,
+ {
+ L"global", no_argument, 0, 'g'
+ }
+ ,
+ {
+ L"local", no_argument, 0, 'l'
+ }
+ ,
+ {
+ L"universal", no_argument, 0, 'U'
+ }
+ ,
+ {
+ L"unexport", no_argument, 0, 'u'
+ }
+ ,
+ {
+ L"prompt", required_argument, 0, 'p'
+ }
+ ,
+ {
+ L"command", required_argument, 0, 'c'
+ }
+ ,
+ {
+ L"mode-name", required_argument, 0, 'm'
+ }
+ ,
+ {
+ L"shell", no_argument, 0, 's'
+ }
+ ,
+ {
+ L"help", no_argument, 0, 'h'
+ }
+ ,
+ {
+ 0, 0, 0, 0
+ }
+ }
+ ;
- woptind=0;
+ int opt_index = 0;
- while( 1 )
- {
- static const struct woption
- long_options[] =
- {
- {
- L"export", no_argument, 0, 'x'
- }
- ,
- {
- L"global", no_argument, 0, 'g'
- }
- ,
- {
- L"local", no_argument, 0, 'l'
- }
- ,
- {
- L"universal", no_argument, 0, 'U'
- }
- ,
- {
- L"unexport", no_argument, 0, 'u'
- }
- ,
- {
- L"prompt", required_argument, 0, 'p'
- }
- ,
- {
- L"command", required_argument, 0, 'c'
- }
- ,
- {
- L"mode-name", required_argument, 0, 'm'
- }
- ,
- {
- L"shell", no_argument, 0, 's'
- }
- ,
- {
- L"help", no_argument, 0, 'h'
- }
- ,
- {
- 0, 0, 0, 0
- }
- }
- ;
+ int opt = wgetopt_long( argc,
+ argv,
+ L"xglUup:c:hm:s",
+ long_options,
+ &opt_index );
+ if( opt == -1 )
+ break;
- int opt_index = 0;
-
- int opt = wgetopt_long( argc,
- argv,
- L"xglUup:c:hm:s",
- long_options,
- &opt_index );
- if( opt == -1 )
- break;
-
- switch( opt )
- {
- case 0:
- if(long_options[opt_index].flag != 0)
- break;
+ switch( opt )
+ {
+ case 0:
+ if(long_options[opt_index].flag != 0)
+ break;
append_format(stderr_buffer,
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name );
- builtin_print_help( parser, argv[0], stderr_buffer );
+ builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
+ return STATUS_BUILTIN_ERROR;
- case L'x':
- place |= ENV_EXPORT;
- break;
+ case L'x':
+ place |= ENV_EXPORT;
+ break;
- case L'g':
- place |= ENV_GLOBAL;
- break;
+ case L'g':
+ place |= ENV_GLOBAL;
+ break;
- case L'l':
- place |= ENV_LOCAL;
- break;
+ case L'l':
+ place |= ENV_LOCAL;
+ break;
- case L'U':
- place |= ENV_UNIVERSAL;
- break;
+ case L'U':
+ place |= ENV_UNIVERSAL;
+ break;
- case L'u':
- place |= ENV_UNEXPORT;
- break;
+ case L'u':
+ place |= ENV_UNEXPORT;
+ break;
- case L'p':
- prompt = woptarg;
- break;
+ case L'p':
+ prompt = woptarg;
+ break;
- case L'c':
- commandline = woptarg;
- break;
+ case L'c':
+ commandline = woptarg;
+ break;
- case L'm':
- mode_name = woptarg;
- break;
+ case L'm':
+ mode_name = woptarg;
+ break;
- case 's':
- shell = 1;
- break;
+ case 's':
+ shell = 1;
+ break;
+
+ case 'h':
+ builtin_print_help( parser, argv[0], stdout_buffer );
+ return STATUS_BUILTIN_OK;
- case 'h':
- builtin_print_help( parser, argv[0], stdout_buffer );
- return STATUS_BUILTIN_OK;
+ case L'?':
+ builtin_unknown_option( parser, argv[0], argv[woptind-1] );
+ return STATUS_BUILTIN_ERROR;
+ }
- case L'?':
- builtin_unknown_option( parser, argv[0], argv[woptind-1] );
- return STATUS_BUILTIN_ERROR;
- }
+ }
- }
-
- if( ( place & ENV_UNEXPORT ) && ( place & ENV_EXPORT ) )
- {
- append_format(stderr_buffer,
- BUILTIN_ERR_EXPUNEXP,
- argv[0] );
+ if( ( place & ENV_UNEXPORT ) && ( place & ENV_EXPORT ) )
+ {
+ append_format(stderr_buffer,
+ BUILTIN_ERR_EXPUNEXP,
+ argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
- if( (place&ENV_LOCAL?1:0) + (place & ENV_GLOBAL?1:0) + (place & ENV_UNIVERSAL?1:0) > 1)
- {
- append_format(stderr_buffer,
- BUILTIN_ERR_GLOCAL,
- argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
+ if( (place&ENV_LOCAL?1:0) + (place & ENV_GLOBAL?1:0) + (place & ENV_UNIVERSAL?1:0) > 1)
+ {
+ append_format(stderr_buffer,
+ BUILTIN_ERR_GLOCAL,
+ argv[0] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
+ return STATUS_BUILTIN_ERROR;
+ }
- /*
- Verify all variable names
- */
- for( i=woptind; i= 0 && (size_t)opt_index < sizeof long_options / sizeof *long_options);
- if(long_options[opt_index].flag != 0)
- break;
- append_format(stderr_buffer,
- BUILTIN_ERR_UNKNOWN,
- argv[0],
- long_options[opt_index].name );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
+ if(long_options[opt_index].flag != 0)
+ break;
+ append_format(stderr_buffer,
+ BUILTIN_ERR_UNKNOWN,
+ argv[0],
+ long_options[opt_index].name );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
- case 'h':
- builtin_print_help( parser, argv[0], stdout_buffer );
- return STATUS_BUILTIN_OK;
+ case 'h':
+ builtin_print_help( parser, argv[0], stdout_buffer );
+ return STATUS_BUILTIN_OK;
- case ':':
- builtin_missing_argument( parser, argv[0], argv[woptind-1] );
- return STATUS_BUILTIN_ERROR;
+ case ':':
+ builtin_missing_argument( parser, argv[0], argv[woptind-1] );
+ return STATUS_BUILTIN_ERROR;
- case '?':
- builtin_unknown_option( parser, argv[0], argv[woptind-1] );
- return STATUS_BUILTIN_ERROR;
+ case '?':
+ builtin_unknown_option( parser, argv[0], argv[woptind-1] );
+ return STATUS_BUILTIN_ERROR;
- case 'i':
- index=1;
- break;
- }
-
- }
+ case 'i':
+ index=1;
+ break;
+ }
+
+ }
- needle = argv[woptind];
- if (!needle)
- {
- append_format(stderr_buffer, _( L"%ls: Key not specified\n" ), argv[0] );
- }
+ needle = argv[woptind];
+ if (!needle)
+ {
+ append_format(stderr_buffer, _( L"%ls: Key not specified\n" ), argv[0] );
+ }
+
-
- for( i=woptind+1; i2)?(argv+2):(argv+1), wcstring_list_t());
+
+ res = reader_read( fd, real_io ? *real_io : io_chain_t() );
+
+ parser.pop_block();
+
+ if( res )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Error while reading file '%ls'\n" ),
+ argv[0],
+ fn_intern == intern_static(L"-") ? L"" : fn_intern );
+ }
+ else
+ {
+ res = proc_get_last_status();
+ }
+
+ /*
+ Do not close fd after calling reader_read. reader_read
+ automatically closes it before calling eval.
+ */
+
+ reader_pop_current_filename();
- fn = wrealpath( argv[1], 0 );
-
- if( !fn )
- {
- fn_intern = intern( argv[1] );
- }
- else
- {
- fn_intern = intern(fn);
- free( (void *)fn );
- }
-
- }
-
- parser.push_block( new source_block_t(fn_intern) );
- reader_push_current_filename( fn_intern );
-
- parse_util_set_argv( (argc>2)?(argv+2):(argv+1), wcstring_list_t());
-
- res = reader_read( fd, real_io ? *real_io : io_chain_t() );
-
- parser.pop_block();
-
- if( res )
- {
- append_format(stderr_buffer,
- _( L"%ls: Error while reading file '%ls'\n" ),
- argv[0],
- fn_intern == intern_static(L"-") ? L"" : fn_intern );
- }
- else
- {
- res = proc_get_last_status();
- }
-
- /*
- Do not close fd after calling reader_read. reader_read
- automatically closes it before calling eval.
- */
-
- reader_pop_current_filename();
-
- return res;
+ return res;
}
/**
@@ -3059,146 +3061,146 @@ static void make_first( job_t *j )
*/
static int builtin_fg( parser_t &parser, wchar_t **argv )
{
- job_t *j=NULL;
-
- if( argv[1] == 0 )
- {
- /*
- Select last constructed job (I.e. first job in the job que)
- that is possible to put in the foreground
- */
+ job_t *j=NULL;
+ if( argv[1] == 0 )
+ {
+ /*
+ Select last constructed job (I.e. first job in the job que)
+ that is possible to put in the foreground
+ */
+
job_iterator_t jobs;
while ((j = jobs.next()))
- {
- if( job_get_flag( j, JOB_CONSTRUCTED ) && (!job_is_completed(j)) &&
- ( (job_is_stopped(j) || (!job_get_flag(j, JOB_FOREGROUND)) ) && job_get_flag( j, JOB_CONTROL) ) )
- {
- break;
- }
- }
- if( !j )
- {
- append_format(stderr_buffer,
- _( L"%ls: There are no suitable jobs\n" ),
- argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- }
- }
- 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
- */
- wchar_t *endptr;
- int pid;
- int found_job = 0;
+ {
+ if( job_get_flag( j, JOB_CONSTRUCTED ) && (!job_is_completed(j)) &&
+ ( (job_is_stopped(j) || (!job_get_flag(j, JOB_FOREGROUND)) ) && job_get_flag( j, JOB_CONTROL) ) )
+ {
+ break;
+ }
+ }
+ if( !j )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: There are no suitable jobs\n" ),
+ argv[0] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ }
+ }
+ 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
+ */
+ wchar_t *endptr;
+ int pid;
+ int found_job = 0;
+
+ errno = 0;
+ pid = fish_wcstoi( argv[1], &endptr, 10 );
+ if( !( *endptr || errno ) )
+ {
+ j = job_get_from_pid( pid );
+ if( j )
+ found_job = 1;
+ }
+
+ if( found_job )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Ambiguous job\n" ),
+ argv[0] );
+ }
+ else
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: '%ls' is not a job\n" ),
+ argv[0],
+ argv[1] );
+ }
- errno = 0;
- pid = fish_wcstoi( argv[1], &endptr, 10 );
- if( !( *endptr || errno ) )
- {
- j = job_get_from_pid( pid );
- if( j )
- found_job = 1;
- }
+ builtin_print_help( parser, argv[0], stderr_buffer );
- if( found_job )
- {
- append_format(stderr_buffer,
- _( L"%ls: Ambiguous job\n" ),
- argv[0] );
- }
- else
- {
- append_format(stderr_buffer,
- _( L"%ls: '%ls' is not a job\n" ),
- argv[0],
- argv[1] );
- }
+ j=0;
- builtin_print_help( parser, argv[0], stderr_buffer );
+ }
+ else
+ {
+ wchar_t *end;
+ int pid;
+ errno = 0;
+ pid = abs(fish_wcstoi( argv[1], &end, 10 ));
+
+ if( *end || errno )
+ {
+ append_format(stderr_buffer,
+ BUILTIN_ERR_NOT_NUMBER,
+ argv[0],
+ argv[1] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ }
+ else
+ {
+ j = job_get_from_pid( pid );
+ if( !j || !job_get_flag( j, JOB_CONSTRUCTED ) || job_is_completed( j ))
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: No suitable job: %d\n" ),
+ argv[0],
+ pid );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ j=0;
+ }
+ else if( !job_get_flag( j, JOB_CONTROL) )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ),
+ argv[0],
+ pid,
+ j->command_wcstr() );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ j=0;
+ }
+ }
+ }
- j=0;
+ if( j )
+ {
+ if( builtin_err_redirect )
+ {
+ append_format(stderr_buffer,
+ FG_MSG,
+ j->job_id,
+ j->command_wcstr() );
+ }
+ else
+ {
+ /*
+ If we aren't redirecting, send output to real stderr,
+ since stuff in sb_err won't get printed until the
+ command finishes.
+ */
+ fwprintf( stderr,
+ FG_MSG,
+ j->job_id,
+ j->command_wcstr() );
+ }
- }
- else
- {
- wchar_t *end;
- int pid;
- errno = 0;
- pid = abs(fish_wcstoi( argv[1], &end, 10 ));
+ wchar_t *ft = tok_first( j->command_wcstr() );
+ if( ft != 0 )
+ env_set( L"_", ft, ENV_EXPORT );
+ free(ft);
+ reader_write_title();
- if( *end || errno )
- {
- append_format(stderr_buffer,
- BUILTIN_ERR_NOT_NUMBER,
- argv[0],
- argv[1] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- }
- else
- {
- j = job_get_from_pid( pid );
- if( !j || !job_get_flag( j, JOB_CONSTRUCTED ) || job_is_completed( j ))
- {
- append_format(stderr_buffer,
- _( L"%ls: No suitable job: %d\n" ),
- argv[0],
- pid );
- builtin_print_help( parser, argv[0], stderr_buffer );
- j=0;
- }
- else if( !job_get_flag( j, JOB_CONTROL) )
- {
- append_format(stderr_buffer,
- _( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ),
- argv[0],
- pid,
- j->command_wcstr() );
- builtin_print_help( parser, argv[0], stderr_buffer );
- j=0;
- }
- }
- }
+ make_first( j );
+ job_set_flag( j, JOB_FOREGROUND, 1 );
- if( j )
- {
- if( builtin_err_redirect )
- {
- append_format(stderr_buffer,
- FG_MSG,
- j->job_id,
- j->command_wcstr() );
- }
- else
- {
- /*
- If we aren't redirecting, send output to real stderr,
- since stuff in sb_err won't get printed until the
- command finishes.
- */
- fwprintf( stderr,
- FG_MSG,
- j->job_id,
- j->command_wcstr() );
- }
-
- wchar_t *ft = tok_first( j->command_wcstr() );
- if( ft != 0 )
- env_set( L"_", ft, ENV_EXPORT );
- free(ft);
- reader_write_title();
-
- make_first( j );
- job_set_flag( j, JOB_FOREGROUND, 1 );
-
- job_continue( j, job_is_stopped(j) );
- }
- return j != 0;
+ job_continue( j, job_is_stopped(j) );
+ }
+ return j != 0;
}
/**
@@ -3206,36 +3208,36 @@ static int builtin_fg( parser_t &parser, wchar_t **argv )
*/
static int send_to_bg( parser_t &parser, job_t *j, const wchar_t *name )
{
- if( j == 0 )
- {
- append_format(stderr_buffer,
- _( L"%ls: Unknown job '%ls'\n" ),
- L"bg",
- name );
- builtin_print_help( parser, L"bg", stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
- else if( !job_get_flag( j, JOB_CONTROL ) )
- {
- append_format(stderr_buffer,
- _( 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_wcstr() );
- builtin_print_help( parser, L"bg", stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
- else
- {
- append_format(stderr_buffer,
- _(L"Send job %d '%ls' to background\n"),
- j->job_id,
- j->command_wcstr() );
- }
- make_first( j );
- job_set_flag( j, JOB_FOREGROUND, 0 );
- job_continue( j, job_is_stopped(j) );
- return STATUS_BUILTIN_OK;
+ if( j == 0 )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Unknown job '%ls'\n" ),
+ L"bg",
+ name );
+ builtin_print_help( parser, L"bg", stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
+ else if( !job_get_flag( j, JOB_CONTROL ) )
+ {
+ append_format(stderr_buffer,
+ _( 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_wcstr() );
+ builtin_print_help( parser, L"bg", stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
+ else
+ {
+ append_format(stderr_buffer,
+ _(L"Send job %d '%ls' to background\n"),
+ j->job_id,
+ j->command_wcstr() );
+ }
+ make_first( j );
+ job_set_flag( j, JOB_FOREGROUND, 0 );
+ job_continue( j, job_is_stopped(j) );
+ return STATUS_BUILTIN_OK;
}
@@ -3244,65 +3246,65 @@ static int send_to_bg( parser_t &parser, job_t *j, const wchar_t *name )
*/
static int builtin_bg( parser_t &parser, wchar_t **argv )
{
- int res = STATUS_BUILTIN_OK;
+ int res = STATUS_BUILTIN_OK;
- if( argv[1] == 0 )
- {
- job_t *j;
+ if( argv[1] == 0 )
+ {
+ job_t *j;
job_iterator_t jobs;
while ((j = jobs.next()))
{
- if( job_is_stopped(j) && job_get_flag( j, JOB_CONTROL ) && (!job_is_completed(j)) )
- {
- break;
- }
- }
+ if( job_is_stopped(j) && job_get_flag( j, JOB_CONTROL ) && (!job_is_completed(j)) )
+ {
+ break;
+ }
+ }
+
+ if( !j )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: There are no suitable jobs\n" ),
+ argv[0] );
+ res = 1;
+ }
+ else
+ {
+ res = send_to_bg( parser, j, _(L"(default)" ) );
+ }
+ }
+ else
+ {
+ wchar_t *end;
+ int i;
+ int pid;
+ int err = 0;
+
+ for( i=1; argv[i]; i++ )
+ {
+ errno=0;
+ pid = fish_wcstoi( argv[i], &end, 10 );
+ if( errno || pid < 0 || *end || !job_get_from_pid( pid ) )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: '%ls' is not a job\n" ),
+ argv[0],
+ argv[i] );
+ err = 1;
+ break;
+ }
+ }
- if( !j )
- {
- append_format(stderr_buffer,
- _( L"%ls: There are no suitable jobs\n" ),
- argv[0] );
- res = 1;
- }
- else
- {
- res = send_to_bg( parser, j, _(L"(default)" ) );
- }
- }
- else
- {
- wchar_t *end;
- int i;
- int pid;
- int err = 0;
-
- for( i=1; argv[i]; i++ )
- {
- errno=0;
- pid = fish_wcstoi( argv[i], &end, 10 );
- if( errno || pid < 0 || *end || !job_get_from_pid( pid ) )
- {
- append_format(stderr_buffer,
- _( L"%ls: '%ls' is not a job\n" ),
- argv[0],
- argv[i] );
- err = 1;
- break;
- }
- }
-
- if( !err )
- {
- for( i=1; !res && argv[i]; i++ )
- {
- pid = fish_wcstoi( argv[i], 0, 10 );
- res |= send_to_bg( parser, job_get_from_pid( pid ), *argv);
- }
- }
- }
-
- return res;
+ if( !err )
+ {
+ for( i=1; !res && argv[i]; i++ )
+ {
+ pid = fish_wcstoi( argv[i], 0, 10 );
+ res |= send_to_bg( parser, job_get_from_pid( pid ), *argv);
+ }
+ }
+ }
+
+ return res;
}
@@ -3311,65 +3313,65 @@ static int builtin_bg( parser_t &parser, wchar_t **argv )
*/
static int builtin_for( parser_t &parser, wchar_t **argv )
{
- int argc = builtin_count_args( argv );
- int res=STATUS_BUILTIN_ERROR;
+ int argc = builtin_count_args( argv );
+ int res=STATUS_BUILTIN_ERROR;
- if( argc < 3)
- {
- append_format(stderr_buffer,
- BUILTIN_FOR_ERR_COUNT,
- argv[0] ,
- argc );
- builtin_print_help( parser, argv[0], stderr_buffer );
- }
- else if ( wcsvarname(argv[1]) )
- {
- append_format(stderr_buffer,
- BUILTIN_FOR_ERR_NAME,
- argv[0],
- argv[1] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- }
- else if (wcscmp( argv[2], L"in") != 0 )
- {
- append_format(stderr_buffer,
- BUILTIN_FOR_ERR_IN,
- argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- }
- else
- {
- res=0;
- }
+ if( argc < 3)
+ {
+ append_format(stderr_buffer,
+ BUILTIN_FOR_ERR_COUNT,
+ argv[0] ,
+ argc );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ }
+ else if ( wcsvarname(argv[1]) )
+ {
+ append_format(stderr_buffer,
+ BUILTIN_FOR_ERR_NAME,
+ argv[0],
+ argv[1] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ }
+ else if (wcscmp( argv[2], L"in") != 0 )
+ {
+ append_format(stderr_buffer,
+ BUILTIN_FOR_ERR_IN,
+ argv[0] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ }
+ else
+ {
+ res=0;
+ }
- if( res )
- {
- parser.push_block( new fake_block_t() );
- }
- else
- {
+ if( res )
+ {
+ parser.push_block( new fake_block_t() );
+ }
+ else
+ {
const wchar_t *for_variable = argv[1];
for_block_t *fb = new for_block_t(for_variable);
- parser.push_block( fb );
- fb->tok_pos = parser.get_pos();
+ parser.push_block( fb );
+ fb->tok_pos = parser.get_pos();
/* Note that we store the sequence of values in opposite order */
wcstring_list_t &for_vars = fb->sequence;
- for( int i=argc-1; i>3; i-- )
+ for( int i=argc-1; i>3; i-- )
for_vars.push_back(argv[i]);
- if( argc > 3 )
- {
- env_set( for_variable, argv[3], ENV_LOCAL );
- }
- else
- {
- parser.current_block->skip=1;
- }
- }
- return res;
+ if( argc > 3 )
+ {
+ env_set( for_variable, argv[3], ENV_LOCAL );
+ }
+ else
+ {
+ parser.current_block->skip=1;
+ }
+ }
+ return res;
}
/**
@@ -3377,9 +3379,9 @@ static int builtin_for( parser_t &parser, wchar_t **argv )
*/
static int builtin_begin( parser_t &parser, wchar_t **argv )
{
- parser.push_block( new scope_block_t(BEGIN) );
- parser.current_block->tok_pos = parser.get_pos();
- return proc_get_last_status();
+ parser.push_block( new scope_block_t(BEGIN) );
+ parser.current_block->tok_pos = parser.get_pos();
+ return proc_get_last_status();
}
@@ -3390,93 +3392,93 @@ static int builtin_begin( parser_t &parser, wchar_t **argv )
*/
static int builtin_end( parser_t &parser, wchar_t **argv )
{
- if( !parser.current_block->outer )
- {
- append_format(stderr_buffer,
- _( L"%ls: Not inside of block\n" ),
- argv[0] );
+ if( !parser.current_block->outer )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Not inside of block\n" ),
+ argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
- 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;
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
+ 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( parser.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( !( parser.current_block->skip && (parser.current_block->loop_status != LOOP_CONTINUE )))
- {
- parser.current_block->loop_status = LOOP_NORMAL;
- parser.current_block->skip = 0;
- kill_block = 0;
- parser.set_pos( parser.current_block->tok_pos);
+ switch( parser.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( !( parser.current_block->skip && (parser.current_block->loop_status != LOOP_CONTINUE )))
+ {
+ parser.current_block->loop_status = LOOP_NORMAL;
+ parser.current_block->skip = 0;
+ kill_block = 0;
+ parser.set_pos( parser.current_block->tok_pos);
while_block_t *blk = static_cast(parser.current_block);
blk->status = WHILE_TEST_AGAIN;
- }
+ }
- break;
- }
+ break;
+ }
- case IF:
- case SUBST:
- case BEGIN:
+ case IF:
+ case SUBST:
+ case BEGIN:
case SWITCH:
case FAKE:
- /*
- Nothing special happens at the end of these commands. The scope just ends.
- */
+ /*
+ Nothing special happens at the end of these commands. The scope just ends.
+ */
- break;
+ break;
- case FOR:
- {
- /*
- set loop variable to next element, and rewind to the beginning of the block.
- */
+ case FOR:
+ {
+ /*
+ set loop variable to next element, and rewind to the beginning of the block.
+ */
for_block_t *fb = static_cast(parser.current_block);
wcstring_list_t &for_vars = fb->sequence;
- if( parser.current_block->loop_status == LOOP_BREAK )
- {
+ if( parser.current_block->loop_status == LOOP_BREAK )
+ {
for_vars.clear();
- }
+ }
- if( ! for_vars.empty() )
- {
+ if( ! for_vars.empty() )
+ {
const wcstring val = for_vars.back();
for_vars.pop_back();
const wcstring &for_variable = fb->variable;
- env_set( for_variable.c_str(), val.c_str(), ENV_LOCAL);
- parser.current_block->loop_status = LOOP_NORMAL;
- parser.current_block->skip = 0;
-
- kill_block = 0;
- parser.set_pos( parser.current_block->tok_pos );
- }
- break;
- }
-
- case FUNCTION_DEF:
- {
- function_def_block_t *fdb = static_cast(parser.current_block);
- function_data_t &d = fdb->function_data;
+ env_set( for_variable.c_str(), val.c_str(), ENV_LOCAL);
+ parser.current_block->loop_status = LOOP_NORMAL;
+ parser.current_block->skip = 0;
+
+ kill_block = 0;
+ parser.set_pos( parser.current_block->tok_pos );
+ }
+ break;
+ }
+ case FUNCTION_DEF:
+ {
+ function_def_block_t *fdb = static_cast(parser.current_block);
+ function_data_t &d = fdb->function_data;
+
if (d.name.empty())
{
/* Disallow empty function names */
append_format(stderr_buffer, _( L"%ls: No function name given\n" ), argv[0] );
-
+
/* Return an error via a crummy way. Don't just return here, since we need to pop the block. */
proc_set_last_status(STATUS_BUILTIN_ERROR);
}
@@ -3491,28 +3493,28 @@ static int builtin_end( parser_t &parser, wchar_t **argv )
wchar_t *def = wcsndup( parser.get_buffer()+parser.current_block->tok_pos,
parser.get_job_pos()-parser.current_block->tok_pos );
d.definition = def;
-
- function_add( d, parser );
+
+ function_add( d, parser );
free( def );
}
- }
- break;
-
+ }
+ break;
+
default:
assert(false); //should never get here
break;
- }
- if( kill_block )
- {
- parser.pop_block();
- }
+ }
+ if( kill_block )
+ {
+ parser.pop_block();
+ }
- /*
- If everything goes ok, return status of last command to execute.
- */
- return proc_get_last_status();
- }
+ /*
+ If everything goes ok, return status of last command to execute.
+ */
+ return proc_get_last_status();
+ }
}
/**
@@ -3531,29 +3533,29 @@ static int builtin_else( parser_t &parser, wchar_t **argv )
block_ok = true;
}
}
-
- if( ! block_ok )
- {
- append_format(stderr_buffer,
- _( L"%ls: Not inside of 'if' block\n" ),
- argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
- else
- {
+
+ if( ! block_ok )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Not inside of 'if' block\n" ),
+ argv[0] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
+ else
+ {
/* Run the else block if the IF expression was false and so were all the ELSEIF expressions (if any) */
bool run_else = ! if_block->any_branch_taken;
- if_block->skip = ! run_else;
+ if_block->skip = ! run_else;
if_block->else_evaluated = true;
- env_pop();
- env_push(0);
- }
+ env_pop();
+ env_push(0);
+ }
- /*
- If everything goes ok, return status of last command to execute.
- */
- return proc_get_last_status();
+ /*
+ If everything goes ok, return status of last command to execute.
+ */
+ return proc_get_last_status();
}
/**
@@ -3562,49 +3564,49 @@ static int builtin_else( parser_t &parser, wchar_t **argv )
*/
static int builtin_break_continue( parser_t &parser, wchar_t **argv )
{
- int is_break = (wcscmp(argv[0],L"break")==0);
- int argc = builtin_count_args( argv );
+ int is_break = (wcscmp(argv[0],L"break")==0);
+ int argc = builtin_count_args( argv );
- block_t *b = parser.current_block;
+ block_t *b = parser.current_block;
- if( argc != 1 )
- {
- append_format(stderr_buffer,
- BUILTIN_ERR_UNKNOWN,
- argv[0],
- argv[1] );
+ if( argc != 1 )
+ {
+ append_format(stderr_buffer,
+ BUILTIN_ERR_UNKNOWN,
+ argv[0],
+ argv[1] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
- while( (b != 0) &&
- ( b->type() != WHILE) &&
- (b->type() != FOR ) )
- {
- b = b->outer;
- }
+ while( (b != 0) &&
+ ( b->type() != WHILE) &&
+ (b->type() != FOR ) )
+ {
+ b = b->outer;
+ }
- if( b == 0 )
- {
- append_format(stderr_buffer,
- _( L"%ls: Not inside of loop\n" ),
- argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
+ if( b == 0 )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Not inside of loop\n" ),
+ argv[0] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
- b = parser.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 STATUS_BUILTIN_OK;
+ b = parser.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 STATUS_BUILTIN_OK;
}
/**
@@ -3614,13 +3616,13 @@ static int builtin_break_continue( parser_t &parser, wchar_t **argv )
static int builtin_breakpoint( parser_t &parser, wchar_t **argv )
{
- parser.push_block( new breakpoint_block_t() );
-
- reader_read( STDIN_FILENO, real_io ? *real_io : io_chain_t() );
-
- parser.pop_block();
-
- return proc_get_last_status();
+ parser.push_block( new breakpoint_block_t() );
+
+ reader_read( STDIN_FILENO, real_io ? *real_io : io_chain_t() );
+
+ parser.pop_block();
+
+ return proc_get_last_status();
}
@@ -3629,67 +3631,67 @@ static int builtin_breakpoint( parser_t &parser, wchar_t **argv )
*/
static int builtin_return( parser_t &parser, wchar_t **argv )
{
- int argc = builtin_count_args( argv );
- int status = proc_get_last_status();
+ int argc = builtin_count_args( argv );
+ int status = proc_get_last_status();
- block_t *b = parser.current_block;
+ block_t *b = parser.current_block;
- switch( argc )
- {
- case 1:
- break;
- case 2:
- {
- wchar_t *end;
- errno = 0;
- status = fish_wcstoi(argv[1],&end,10);
- if( errno || *end != 0)
- {
- append_format(stderr_buffer,
- _( L"%ls: Argument '%ls' must be an integer\n" ),
- argv[0],
- argv[1] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
- break;
- }
- default:
- append_format(stderr_buffer,
- _( L"%ls: Too many arguments\n" ),
- argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
+ switch( argc )
+ {
+ case 1:
+ break;
+ case 2:
+ {
+ wchar_t *end;
+ errno = 0;
+ status = fish_wcstoi(argv[1],&end,10);
+ if( errno || *end != 0)
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Argument '%ls' must be an integer\n" ),
+ argv[0],
+ argv[1] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
+ break;
+ }
+ default:
+ append_format(stderr_buffer,
+ _( L"%ls: Too many arguments\n" ),
+ argv[0] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
- while( (b != 0) &&
- ( b->type() != FUNCTION_CALL &&
- b->type() != FUNCTION_CALL_NO_SHADOW) )
- {
- b = b->outer;
- }
+ while( (b != 0) &&
+ ( b->type() != FUNCTION_CALL &&
+ b->type() != FUNCTION_CALL_NO_SHADOW) )
+ {
+ b = b->outer;
+ }
- if( b == 0 )
- {
- append_format(stderr_buffer,
- _( L"%ls: Not inside of function\n" ),
- argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
+ if( b == 0 )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Not inside of function\n" ),
+ argv[0] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
- b = parser.current_block;
- while( ( b->type() != FUNCTION_CALL &&
- b->type() != FUNCTION_CALL_NO_SHADOW ) )
- {
+ b = parser.current_block;
+ while( ( b->type() != FUNCTION_CALL &&
+ b->type() != FUNCTION_CALL_NO_SHADOW ) )
+ {
b->mark_as_fake();
- b->skip=1;
- b = b->outer;
- }
- b->skip=1;
+ b->skip=1;
+ b = b->outer;
+ }
+ b->skip=1;
- return status;
+ return status;
}
/**
@@ -3698,28 +3700,28 @@ static int builtin_return( parser_t &parser, wchar_t **argv )
*/
static int builtin_switch( parser_t &parser, wchar_t **argv )
{
- int res=STATUS_BUILTIN_OK;
- int argc = builtin_count_args( argv );
+ int res=STATUS_BUILTIN_OK;
+ int argc = builtin_count_args( argv );
- if( argc != 2 )
- {
- append_format(stderr_buffer,
- _( L"%ls: Expected exactly one argument, got %d\n" ),
- argv[0],
- argc-1 );
+ if( argc != 2 )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: Expected exactly one argument, got %d\n" ),
+ argv[0],
+ argc-1 );
- builtin_print_help( parser, argv[0], stderr_buffer );
- res=1;
- parser.push_block( new fake_block_t() );
- }
- else
- {
- parser.push_block( new switch_block_t(argv[1]) );
- parser.current_block->skip=1;
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ res=1;
+ parser.push_block( new fake_block_t() );
+ }
+ else
+ {
+ parser.push_block( new switch_block_t(argv[1]) );
+ parser.current_block->skip=1;
res = proc_get_last_status();
- }
-
- return res;
+ }
+
+ return res;
}
/**
@@ -3728,44 +3730,44 @@ static int builtin_switch( parser_t &parser, wchar_t **argv )
*/
static int builtin_case( parser_t &parser, wchar_t **argv )
{
- int argc = builtin_count_args( argv );
- int i;
- wchar_t *unescaped=0;
-
- if( parser.current_block->type() != SWITCH )
- {
- append_format(stderr_buffer,
- _( L"%ls: 'case' command while not in switch block\n" ),
- argv[0] );
- builtin_print_help( parser, argv[0], stderr_buffer );
- return STATUS_BUILTIN_ERROR;
- }
-
- parser.current_block->skip = 1;
- switch_block_t *sb = static_cast(parser.current_block);
- if( sb->switch_taken )
- {
- return proc_get_last_status();
- }
-
+ int argc = builtin_count_args( argv );
+ int i;
+ wchar_t *unescaped=0;
+
+ if( parser.current_block->type() != SWITCH )
+ {
+ append_format(stderr_buffer,
+ _( L"%ls: 'case' command while not in switch block\n" ),
+ argv[0] );
+ builtin_print_help( parser, argv[0], stderr_buffer );
+ return STATUS_BUILTIN_ERROR;
+ }
+
+ parser.current_block->skip = 1;
+ switch_block_t *sb = static_cast(parser.current_block);
+ if( sb->switch_taken )
+ {
+ return proc_get_last_status();
+ }
+
const wcstring &switch_value = sb->switch_value;
- for( i=1; iskip = 0;
- sb->switch_taken = true;
- break;
- }
- }
-
- return proc_get_last_status();
+ for( i=1; iskip = 0;
+ sb->switch_taken = true;
+ break;
+ }
+ }
+
+ return proc_get_last_status();
}
@@ -3776,7 +3778,7 @@ static int builtin_history( parser_t &parser, wchar_t **argv )
{
int argc = builtin_count_args(argv);
- bool search_history = false;
+ bool search_history = false;
bool delete_item = false;
bool search_prefix = false;
bool save_history = false;
@@ -3798,11 +3800,11 @@ static int builtin_history( parser_t &parser, wchar_t **argv )
int opt_index = 0;
woptind = 0;
history_t *history = reader_get_history();
-
+
/* Use the default history if we have none (which happens if invoked non-interactively, e.g. from webconfig.py */
if (! history)
history = &history_t::history_with_name(L"fish");
-
+
while((opt = wgetopt_long_only( argc, argv, L"pdscvl", long_options, &opt_index )) != -1)
{
switch(opt)
@@ -3823,7 +3825,7 @@ static int builtin_history( parser_t &parser, wchar_t **argv )
break;
case 'l':
clear_history = true;
- break;
+ break;
case 'h':
builtin_print_help( parser, argv[0], stdout_buffer );
return STATUS_BUILTIN_OK;
@@ -3839,7 +3841,7 @@ static int builtin_history( parser_t &parser, wchar_t **argv )
append_format(stderr_buffer, BUILTIN_ERR_UNKNOWN, argv[0], argv[woptind-1]);
return STATUS_BUILTIN_ERROR;
}
- }
+ }
/* Everything after is an argument */
const wcstring_list_t args(argv + woptind, argv + argc);
@@ -3869,7 +3871,7 @@ static int builtin_history( parser_t &parser, wchar_t **argv )
while (searcher.go_backwards())
{
stdout_buffer.append(searcher.current_string());
- stdout_buffer.append(L"\n");
+ stdout_buffer.append(L"\n");
res = STATUS_BUILTIN_OK;
}
}
@@ -3883,7 +3885,7 @@ static int builtin_history( parser_t &parser, wchar_t **argv )
wcstring delete_string = *iter;
if (delete_string[0] == '"' && delete_string[delete_string.length() - 1] == '"')
delete_string = delete_string.substr(1, delete_string.length() - 2);
-
+
history->remove(delete_string);
}
return STATUS_BUILTIN_OK;
@@ -3919,48 +3921,48 @@ static int builtin_history( parser_t &parser, wchar_t **argv )
*/
static const builtin_data_t builtin_datas[]=
{
- { L".", &builtin_source, N_( L"Evaluate contents of file" ) },
- { L"and", &builtin_generic, N_( L"Execute command if previous command suceeded" ) },
- { L"begin", &builtin_begin, N_( L"Create a block of code" ) },
- { L"bg", &builtin_bg, N_( L"Send job to background" ) },
- { L"bind", &builtin_bind, N_( L"Handle fish key bindings" ) },
- { L"block", &builtin_block, N_( L"Temporarily block delivery of events" ) },
- { L"break", &builtin_break_continue, N_( L"Stop the innermost loop" ) },
- { L"breakpoint", &builtin_breakpoint, N_( L"Temporarily halt execution of a script and launch an interactive debug prompt" ) },
- { L"builtin", &builtin_builtin, N_( L"Run a builtin command instead of a function" ) },
- { L"case", &builtin_case, N_( L"Conditionally execute a block of commands" ) },
- { L"cd", &builtin_cd, N_( L"Change working directory" ) },
- { L"command", &builtin_generic, N_( L"Run a program instead of a function or builtin" ) },
- { L"commandline", &builtin_commandline, N_( L"Set or get the commandline" ) },
- { L"complete", &builtin_complete, N_( L"Edit command specific completions" ) },
- { L"contains", &builtin_contains, N_( L"Search for a specified string in a list" ) },
- { L"continue", &builtin_break_continue, N_( L"Skip the rest of the current lap of the innermost loop" ) },
- { L"count", &builtin_count, N_( L"Count the number of arguments" ) },
- { L"echo", &builtin_echo, N_( L"Print arguments" ) },
- { L"else", &builtin_else, N_( L"Evaluate block if condition is false" ) },
- { L"emit", &builtin_emit, N_( L"Emit an event" ) },
- { L"end", &builtin_end, N_( L"End a block of commands" ) },
- { L"exec", &builtin_generic, N_( L"Run command in current process" ) },
- { L"exit", &builtin_exit, N_( L"Exit the shell" ) },
- { L"fg", &builtin_fg, N_( L"Send job to foreground" ) },
- { L"for", &builtin_for, N_( L"Perform a set of commands multiple times" ) },
- { L"function", &builtin_function, N_( L"Define a new function" ) },
- { L"functions", &builtin_functions, N_( L"List or remove functions" ) },
- { L"history", &builtin_history, N_( L"History of commands executed by user" ) },
- { L"if", &builtin_generic, N_( L"Evaluate block if condition is true" ) },
- { L"jobs", &builtin_jobs, N_( L"Print currently running jobs" ) },
- { L"not", &builtin_generic, N_( L"Negate exit status of job" ) },
- { L"or", &builtin_generic, N_( L"Execute command if previous command failed" ) },
- { L"pwd", &builtin_pwd, N_( L"Print the working directory" ) },
- { L"random", &builtin_random, N_( L"Generate random number" ) },
- { L"read", &builtin_read, N_( L"Read a line of input into variables" ) },
- { L"return", &builtin_return, N_( L"Stop the currently evaluated function" ) },
- { L"set", &builtin_set, N_( L"Handle environment variables" ) },
- { L"status", &builtin_status, N_( L"Return status information about fish" ) },
- { L"switch", &builtin_switch, N_( L"Conditionally execute a block of commands" ) },
- { L"test", &builtin_test, N_( L"Test a condition" ) },
- { L"ulimit", &builtin_ulimit, N_( L"Set or get the shells resource usage limits" ) },
- { L"while", &builtin_generic, N_( L"Perform a command multiple times" ) }
+ { L".", &builtin_source, N_( L"Evaluate contents of file" ) },
+ { L"and", &builtin_generic, N_( L"Execute command if previous command suceeded" ) },
+ { L"begin", &builtin_begin, N_( L"Create a block of code" ) },
+ { L"bg", &builtin_bg, N_( L"Send job to background" ) },
+ { L"bind", &builtin_bind, N_( L"Handle fish key bindings" ) },
+ { L"block", &builtin_block, N_( L"Temporarily block delivery of events" ) },
+ { L"break", &builtin_break_continue, N_( L"Stop the innermost loop" ) },
+ { L"breakpoint", &builtin_breakpoint, N_( L"Temporarily halt execution of a script and launch an interactive debug prompt" ) },
+ { L"builtin", &builtin_builtin, N_( L"Run a builtin command instead of a function" ) },
+ { L"case", &builtin_case, N_( L"Conditionally execute a block of commands" ) },
+ { L"cd", &builtin_cd, N_( L"Change working directory" ) },
+ { L"command", &builtin_generic, N_( L"Run a program instead of a function or builtin" ) },
+ { L"commandline", &builtin_commandline, N_( L"Set or get the commandline" ) },
+ { L"complete", &builtin_complete, N_( L"Edit command specific completions" ) },
+ { L"contains", &builtin_contains, N_( L"Search for a specified string in a list" ) },
+ { L"continue", &builtin_break_continue, N_( L"Skip the rest of the current lap of the innermost loop" ) },
+ { L"count", &builtin_count, N_( L"Count the number of arguments" ) },
+ { L"echo", &builtin_echo, N_( L"Print arguments" ) },
+ { L"else", &builtin_else, N_( L"Evaluate block if condition is false" ) },
+ { L"emit", &builtin_emit, N_( L"Emit an event" ) },
+ { L"end", &builtin_end, N_( L"End a block of commands" ) },
+ { L"exec", &builtin_generic, N_( L"Run command in current process" ) },
+ { L"exit", &builtin_exit, N_( L"Exit the shell" ) },
+ { L"fg", &builtin_fg, N_( L"Send job to foreground" ) },
+ { L"for", &builtin_for, N_( L"Perform a set of commands multiple times" ) },
+ { L"function", &builtin_function, N_( L"Define a new function" ) },
+ { L"functions", &builtin_functions, N_( L"List or remove functions" ) },
+ { L"history", &builtin_history, N_( L"History of commands executed by user" ) },
+ { L"if", &builtin_generic, N_( L"Evaluate block if condition is true" ) },
+ { L"jobs", &builtin_jobs, N_( L"Print currently running jobs" ) },
+ { L"not", &builtin_generic, N_( L"Negate exit status of job" ) },
+ { L"or", &builtin_generic, N_( L"Execute command if previous command failed" ) },
+ { L"pwd", &builtin_pwd, N_( L"Print the working directory" ) },
+ { L"random", &builtin_random, N_( L"Generate random number" ) },
+ { L"read", &builtin_read, N_( L"Read a line of input into variables" ) },
+ { L"return", &builtin_return, N_( L"Stop the currently evaluated function" ) },
+ { L"set", &builtin_set, N_( L"Handle environment variables" ) },
+ { L"status", &builtin_status, N_( L"Return status information about fish" ) },
+ { L"switch", &builtin_switch, N_( L"Conditionally execute a block of commands" ) },
+ { L"test", &builtin_test, N_( L"Test a condition" ) },
+ { L"ulimit", &builtin_ulimit, N_( L"Set or get the shells resource usage limits" ) },
+ { L"while", &builtin_generic, N_( L"Perform a command multiple times" ) }
};
#define BUILTIN_COUNT (sizeof builtin_datas / sizeof *builtin_datas)
@@ -3977,12 +3979,12 @@ static const builtin_data_t *builtin_lookup(const wcstring &name) {
void builtin_init()
{
-
- wopterr = 0;
- for( size_t i=0; i < BUILTIN_COUNT; i++ )
- {
- intern_static( builtin_datas[i].name );
- }
+
+ wopterr = 0;
+ for( size_t i=0; i < BUILTIN_COUNT; i++ )
+ {
+ intern_static( builtin_datas[i].name );
+ }
}
void builtin_destroy()
@@ -3991,7 +3993,7 @@ void builtin_destroy()
int builtin_exists( const wcstring &cmd )
{
- return !!builtin_lookup(cmd);
+ return !!builtin_lookup(cmd);
}
/**
@@ -4000,45 +4002,45 @@ int builtin_exists( const wcstring &cmd )
*/
static int internal_help( const wchar_t *cmd )
{
- CHECK( cmd, 0 );
- return contains( cmd, L"for", L"while", L"function",
- L"if", L"end", L"switch", L"case", L"count" );
+ CHECK( cmd, 0 );
+ return contains( cmd, L"for", L"while", L"function",
+ L"if", L"end", L"switch", L"case", L"count" );
}
int builtin_run( parser_t &parser, const wchar_t * const *argv, const io_chain_t &io )
{
- int (*cmd)(parser_t &parser, const wchar_t * const *argv)=0;
- real_io = &io;
-
- CHECK( argv, STATUS_BUILTIN_ERROR );
- CHECK( argv[0], STATUS_BUILTIN_ERROR );
-
+ int (*cmd)(parser_t &parser, const wchar_t * const *argv)=0;
+ real_io = &io;
+
+ CHECK( argv, STATUS_BUILTIN_ERROR );
+ CHECK( argv[0], STATUS_BUILTIN_ERROR );
+
const builtin_data_t *data = builtin_lookup(argv[0]);
- cmd = (int (*)(parser_t &parser, const wchar_t * const*))(data ? data->func : NULL);
+ cmd = (int (*)(parser_t &parser, const wchar_t * const*))(data ? data->func : NULL);
+
+ if( argv[1] != 0 && !internal_help(argv[0]) )
+ {
+ if( argv[2] == 0 && (parser.is_help( argv[1], 0 ) ) )
+ {
+ builtin_print_help( parser, argv[0], stdout_buffer );
+ return STATUS_BUILTIN_OK;
+ }
+ }
- if( argv[1] != 0 && !internal_help(argv[0]) )
- {
- if( argv[2] == 0 && (parser.is_help( argv[1], 0 ) ) )
- {
- builtin_print_help( parser, argv[0], stdout_buffer );
- return STATUS_BUILTIN_OK;
- }
- }
+ if( data != NULL )
+ {
+ int status;
- if( data != NULL )
- {
- int status;
+ status = cmd(parser, argv);
+ return status;
- status = cmd(parser, argv);
- return status;
-
- }
- else
- {
- debug( 0, _( L"Unknown builtin '%ls'" ), argv[0] );
- }
- return STATUS_BUILTIN_ERROR;
+ }
+ else
+ {
+ debug( 0, _( L"Unknown builtin '%ls'" ), argv[0] );
+ }
+ return STATUS_BUILTIN_ERROR;
}
@@ -4053,15 +4055,15 @@ wcstring_list_t builtin_get_names(void)
}
void builtin_get_names(std::vector &list) {
- for (size_t i=0; i < BUILTIN_COUNT; i++) {
- list.push_back(completion_t(builtin_datas[i].name));
- }
+ for (size_t i=0; i < BUILTIN_COUNT; i++) {
+ list.push_back(completion_t(builtin_datas[i].name));
+ }
}
wcstring builtin_get_desc( const wcstring &name )
{
wcstring result;
- const builtin_data_t *builtin = builtin_lookup(name);
+ const builtin_data_t *builtin = builtin_lookup(name);
if (builtin) {
result = _(builtin->desc);
}
@@ -4071,12 +4073,12 @@ wcstring builtin_get_desc( const wcstring &name )
void builtin_push_io( parser_t &parser, int in )
{
ASSERT_IS_MAIN_THREAD();
- if( builtin_stdin != -1 )
- {
+ if( builtin_stdin != -1 )
+ {
struct io_stack_elem_t elem = {builtin_stdin, stdout_buffer, stderr_buffer};
io_stack.push(elem);
- }
- builtin_stdin = in;
+ }
+ builtin_stdin = in;
stdout_buffer.clear();
stderr_buffer.clear();
}
@@ -4084,20 +4086,20 @@ void builtin_push_io( parser_t &parser, int in )
void builtin_pop_io(parser_t &parser)
{
ASSERT_IS_MAIN_THREAD();
- builtin_stdin = 0;
- if( ! io_stack.empty() )
- {
+ builtin_stdin = 0;
+ if( ! io_stack.empty() )
+ {
struct io_stack_elem_t &elem = io_stack.top();
- stderr_buffer = elem.err;
- stdout_buffer = elem.out;
- builtin_stdin = elem.in;
+ stderr_buffer = elem.err;
+ stdout_buffer = elem.out;
+ builtin_stdin = elem.in;
io_stack.pop();
- }
- else
- {
+ }
+ else
+ {
stdout_buffer.clear();
stderr_buffer.clear();
- builtin_stdin = 0;
- }
+ builtin_stdin = 0;
+ }
}
diff --git a/common.cpp b/common.cpp
index 3d9a7e475..fce8c459e 100644
--- a/common.cpp
+++ b/common.cpp
@@ -1,5 +1,5 @@
/** \file common.c
-
+
Various functions, mostly string utilities, that are used by most
parts of fish.
*/
@@ -38,7 +38,7 @@ parts of fish.
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -82,7 +82,7 @@ parts of fish.
-struct termios shell_modes;
+struct termios shell_modes;
// Note we foolishly assume that pthread_t is just a primitive. But it might be a struct.
static pthread_t main_thread_id = 0;
@@ -102,78 +102,78 @@ int debug_level=1;
static struct winsize termsize;
-void show_stackframe()
+void show_stackframe()
{
/* Hack to avoid showing backtraces in the tester */
if (program_name && ! wcscmp(program_name, L"(ignore)"))
return;
+
+ void *trace[32];
+ char **messages = (char **)NULL;
+ int i, trace_size = 0;
- void *trace[32];
- char **messages = (char **)NULL;
- int i, trace_size = 0;
+ trace_size = backtrace(trace, 32);
+ messages = backtrace_symbols(trace, trace_size);
- trace_size = backtrace(trace, 32);
- messages = backtrace_symbols(trace, trace_size);
-
- if( messages )
- {
- debug( 0, L"Backtrace:" );
- for( i=0; ipush_back((wchar_t)c);
- break;
- }
- }
+ s->push_back((wchar_t)c);
+ break;
+ }
+ }
}
wchar_t *str2wcs( const char *in )
{
- wchar_t *out;
- size_t len = strlen(in);
+ wchar_t *out;
+ size_t len = strlen(in);
+
+ out = (wchar_t *)malloc( sizeof(wchar_t)*(len+1) );
- out = (wchar_t *)malloc( sizeof(wchar_t)*(len+1) );
+ if( !out )
+ {
+ DIE_MEM();
+ }
- if( !out )
- {
- DIE_MEM();
- }
-
- return str2wcs_internal( in, out );
+ return str2wcs_internal( in, out );
}
wcstring str2wcstring( const char *in )
@@ -194,71 +194,71 @@ wcstring str2wcstring( const std::string &in )
wchar_t *str2wcs_internal( const char *in, wchar_t *out )
{
- size_t res=0;
- size_t in_pos=0;
- size_t out_pos = 0;
- mbstate_t state;
- size_t len;
+ size_t res=0;
+ size_t in_pos=0;
+ size_t out_pos = 0;
+ mbstate_t state;
+ size_t len;
- CHECK( in, 0 );
- CHECK( out, 0 );
+ CHECK( in, 0 );
+ CHECK( out, 0 );
+
+ len = strlen(in);
- len = strlen(in);
+ memset( &state, 0, sizeof(state) );
- memset( &state, 0, sizeof(state) );
+ while( in[in_pos] )
+ {
+ res = mbrtowc( &out[out_pos], &in[in_pos], len-in_pos, &state );
- while( in[in_pos] )
- {
- res = mbrtowc( &out[out_pos], &in[in_pos], len-in_pos, &state );
-
- if( ( ( out[out_pos] >= ENCODE_DIRECT_BASE) &&
- ( out[out_pos] < ENCODE_DIRECT_BASE+256)) ||
- ( out[out_pos] == INTERNAL_SEPARATOR ) )
- {
- out[out_pos] = ENCODE_DIRECT_BASE + (unsigned char)in[in_pos];
- in_pos++;
- memset( &state, 0, sizeof(state) );
- out_pos++;
- }
- else
- {
-
- switch( res )
- {
- case (size_t)(-2):
- case (size_t)(-1):
- {
- out[out_pos] = ENCODE_DIRECT_BASE + (unsigned char)in[in_pos];
- in_pos++;
- memset( &state, 0, sizeof(state) );
- break;
- }
-
- case 0:
- {
- return out;
- }
-
- default:
- {
- in_pos += res;
- break;
- }
- }
- out_pos++;
- }
-
- }
- out[out_pos] = 0;
-
- return out;
+ if( ( ( out[out_pos] >= ENCODE_DIRECT_BASE) &&
+ ( out[out_pos] < ENCODE_DIRECT_BASE+256)) ||
+ ( out[out_pos] == INTERNAL_SEPARATOR ) )
+ {
+ out[out_pos] = ENCODE_DIRECT_BASE + (unsigned char)in[in_pos];
+ in_pos++;
+ memset( &state, 0, sizeof(state) );
+ out_pos++;
+ }
+ else
+ {
+
+ switch( res )
+ {
+ case (size_t)(-2):
+ case (size_t)(-1):
+ {
+ out[out_pos] = ENCODE_DIRECT_BASE + (unsigned char)in[in_pos];
+ in_pos++;
+ memset( &state, 0, sizeof(state) );
+ break;
+ }
+
+ case 0:
+ {
+ return out;
+ }
+
+ default:
+ {
+ in_pos += res;
+ break;
+ }
+ }
+ out_pos++;
+ }
+
+ }
+ out[out_pos] = 0;
+
+ return out;
}
char *wcs2str( const wchar_t *in )
{
if (! in)
return NULL;
- char *out;
+ char *out;
size_t desired_size = MAX_UTF8_BYTES*wcslen(in)+1;
char local_buff[512];
if (desired_size <= sizeof local_buff / sizeof *local_buff) {
@@ -272,7 +272,7 @@ char *wcs2str( const wchar_t *in )
}
}
return result;
-
+
} else {
// here we fall into the bad case of allocating a buffer probably much larger than necessary
out = (char *)malloc( MAX_UTF8_BYTES*wcslen(in)+1 );
@@ -282,7 +282,7 @@ char *wcs2str( const wchar_t *in )
return wcs2str_internal( in, out );
}
- return wcs2str_internal( in, out );
+ return wcs2str_internal( in, out );
}
std::string wcs2string(const wcstring &input)
@@ -295,85 +295,85 @@ std::string wcs2string(const wcstring &input)
char *wcs2str_internal( const wchar_t *in, char *out )
{
- size_t res=0;
- size_t in_pos=0;
- size_t out_pos = 0;
- mbstate_t state;
+ size_t res=0;
+ size_t in_pos=0;
+ size_t out_pos = 0;
+ mbstate_t state;
- CHECK( in, 0 );
- CHECK( out, 0 );
-
- memset( &state, 0, sizeof(state) );
-
- while( in[in_pos] )
- {
- if( in[in_pos] == INTERNAL_SEPARATOR )
- {
- }
- else if( ( in[in_pos] >= ENCODE_DIRECT_BASE) &&
- ( in[in_pos] < ENCODE_DIRECT_BASE+256) )
- {
- out[out_pos++] = in[in_pos]- ENCODE_DIRECT_BASE;
- }
- else
- {
- res = wcrtomb( &out[out_pos], in[in_pos], &state );
-
- if( res == (size_t)(-1) )
- {
- debug( 1, L"Wide character %d has no narrow representation", in[in_pos] );
- memset( &state, 0, sizeof(state) );
- }
- else
- {
- out_pos += res;
- }
- }
- in_pos++;
- }
- out[out_pos] = 0;
-
- return out;
+ CHECK( in, 0 );
+ CHECK( out, 0 );
+
+ memset( &state, 0, sizeof(state) );
+
+ while( in[in_pos] )
+ {
+ if( in[in_pos] == INTERNAL_SEPARATOR )
+ {
+ }
+ else if( ( in[in_pos] >= ENCODE_DIRECT_BASE) &&
+ ( in[in_pos] < ENCODE_DIRECT_BASE+256) )
+ {
+ out[out_pos++] = in[in_pos]- ENCODE_DIRECT_BASE;
+ }
+ else
+ {
+ res = wcrtomb( &out[out_pos], in[in_pos], &state );
+
+ if( res == (size_t)(-1) )
+ {
+ debug( 1, L"Wide character %d has no narrow representation", in[in_pos] );
+ memset( &state, 0, sizeof(state) );
+ }
+ else
+ {
+ out_pos += res;
+ }
+ }
+ in_pos++;
+ }
+ out[out_pos] = 0;
+
+ return out;
}
char **wcsv2strv( const wchar_t * const *in )
{
- size_t i, count = 0;
+ size_t i, count = 0;
- while( in[count] != 0 )
- count++;
- char **res = (char **)malloc( sizeof( char *)*(count+1));
- if( res == 0 )
- {
- DIE_MEM();
- }
+ while( in[count] != 0 )
+ count++;
+ char **res = (char **)malloc( sizeof( char *)*(count+1));
+ if( res == 0 )
+ {
+ DIE_MEM();
+ }
- for( i=0; i= count )
- {
- break;
- }
- }
- return (ssize_t)out_cum;
+ ssize_t out=0;
+ size_t out_cum=0;
+ while( 1 )
+ {
+ out = write( fd,
+ &buff[out_cum],
+ count - out_cum );
+ if (out < 0)
+ {
+ if(errno != EAGAIN && errno != EINTR)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ out_cum += (size_t)out;
+ }
+ if( out_cum >= count )
+ {
+ break;
+ }
+ }
+ return (ssize_t)out_cum;
}
ssize_t read_loop(int fd, void *buff, size_t count)
@@ -611,22 +611,22 @@ ssize_t read_loop(int fd, void *buff, size_t count)
static bool should_debug(int level)
{
- if( level > debug_level )
- return false;
+ if( level > debug_level )
+ return false;
/* Hack to not print error messages in the tests */
if ( program_name && ! wcscmp(program_name, L"(ignore)") )
return false;
-
+
return true;
}
static void debug_shared( const wcstring &msg )
{
const wcstring sb = wcstring(program_name) + L": " + msg;
- wcstring sb2;
- write_screen( sb, sb2 );
- fwprintf( stderr, L"%ls", sb2.c_str() );
+ wcstring sb2;
+ write_screen( sb, sb2 );
+ fwprintf( stderr, L"%ls", sb2.c_str() );
}
void debug( int level, const wchar_t *msg, ... )
@@ -635,9 +635,9 @@ void debug( int level, const wchar_t *msg, ... )
return;
int errno_old = errno;
va_list va;
- va_start(va, msg);
+ va_start(va, msg);
wcstring local_msg = vformat_string(msg, va);
- va_end(va);
+ va_end(va);
debug_shared(local_msg);
errno = errno_old;
}
@@ -649,9 +649,9 @@ void debug( int level, const char *msg, ... )
int errno_old = errno;
char local_msg[512];
va_list va;
- va_start(va, msg);
+ va_start(va, msg);
vsnprintf(local_msg, sizeof local_msg, msg, va);
- va_end(va);
+ va_end(va);
debug_shared(str2wcstring(local_msg));
errno = errno_old;
}
@@ -662,26 +662,26 @@ void debug_safe(int level, const char *msg, const char *param1, const char *para
const char * const params[] = {param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12};
if (! msg)
return;
-
+
/* Can't call printf, that may allocate memory Just call write() over and over. */
if (level > debug_level)
return;
int errno_old = errno;
-
+
size_t param_idx = 0;
const char *cursor = msg;
while (*cursor != '\0') {
const char *end = strchr(cursor, '%');
if (end == NULL)
end = cursor + strlen(cursor);
-
+
write(STDERR_FILENO, cursor, end - cursor);
if (end[0] == '%' && end[1] == 's') {
/* Handle a format string */
assert(param_idx < sizeof params / sizeof *params);
const char *format = params[param_idx++];
- if (! format)
+ if (! format)
format = "(null)";
write(STDERR_FILENO, format, strlen(format));
cursor = end + 2;
@@ -693,10 +693,10 @@ void debug_safe(int level, const char *msg, const char *param1, const char *para
cursor = end + 1;
}
}
-
+
// We always append a newline
write(STDERR_FILENO, "\n", 1);
-
+
errno = errno_old;
}
@@ -707,7 +707,7 @@ void format_long_safe(char buff[128], long val) {
/* Generate the string in reverse */
size_t idx = 0;
bool negative = (val < 0);
-
+
/* Note that we can't just negate val if it's negative, because it may be the most negative value. We do rely on round-towards-zero division though. */
while (val != 0) {
@@ -718,7 +718,7 @@ void format_long_safe(char buff[128], long val) {
if (negative)
buff[idx++] = '-';
buff[idx] = 0;
-
+
size_t left = 0, right = idx - 1;
while (left < right) {
char tmp = buff[left];
@@ -745,7 +745,7 @@ void format_long_safe(wchar_t buff[128], long val) {
if (negative)
buff[idx++] = L'-';
buff[idx] = 0;
-
+
size_t left = 0, right = idx - 1;
while (left < right) {
wchar_t tmp = buff[left];
@@ -757,90 +757,90 @@ void format_long_safe(wchar_t buff[128], long val) {
void write_screen( const wcstring &msg, wcstring &buff )
{
- const wchar_t *start, *pos;
- int line_width = 0;
- int tok_width = 0;
- int screen_width = common_get_width();
+ const wchar_t *start, *pos;
+ int line_width = 0;
+ int tok_width = 0;
+ int screen_width = common_get_width();
+
+ if( screen_width )
+ {
+ start = pos = msg.c_str();
+ while( 1 )
+ {
+ int overflow = 0;
+
+ tok_width=0;
- if( screen_width )
- {
- start = pos = msg.c_str();
- while( 1 )
- {
- int overflow = 0;
+ /*
+ Tokenize on whitespace, and also calculate the width of the token
+ */
+ while( *pos && ( !wcschr( L" \n\r\t", *pos ) ) )
+ {
+
+ /*
+ Check is token is wider than one line.
+ If so we mark it as an overflow and break the token.
+ */
+ if((tok_width + fish_wcwidth(*pos)) > (screen_width-1))
+ {
+ overflow = 1;
+ break;
+ }
+
+ tok_width += fish_wcwidth( *pos );
+ pos++;
+ }
- tok_width=0;
-
- /*
- Tokenize on whitespace, and also calculate the width of the token
- */
- while( *pos && ( !wcschr( L" \n\r\t", *pos ) ) )
- {
-
- /*
- Check is token is wider than one line.
- If so we mark it as an overflow and break the token.
- */
- if((tok_width + fish_wcwidth(*pos)) > (screen_width-1))
- {
- overflow = 1;
- break;
- }
-
- tok_width += fish_wcwidth( *pos );
- pos++;
- }
-
- /*
- If token is zero character long, we don't do anything
- */
- if( pos == start )
- {
- start = pos = pos+1;
- }
- else if( overflow )
- {
- /*
- In case of overflow, we print a newline, except if we already are at position 0
- */
- wchar_t *token = wcsndup( start, pos-start );
- if( line_width != 0 )
+ /*
+ If token is zero character long, we don't do anything
+ */
+ if( pos == start )
+ {
+ start = pos = pos+1;
+ }
+ else if( overflow )
+ {
+ /*
+ In case of overflow, we print a newline, except if we already are at position 0
+ */
+ wchar_t *token = wcsndup( start, pos-start );
+ if( line_width != 0 )
buff.push_back(L'\n');
buff.append(format_string(L"%ls-\n", token));
- free( token );
- line_width=0;
- }
- else
- {
- /*
- Print the token
- */
- wchar_t *token = wcsndup( start, pos-start );
- if( (line_width + (line_width!=0?1:0) + tok_width) > screen_width )
- {
+ free( token );
+ line_width=0;
+ }
+ else
+ {
+ /*
+ Print the token
+ */
+ wchar_t *token = wcsndup( start, pos-start );
+ if( (line_width + (line_width!=0?1:0) + tok_width) > screen_width )
+ {
buff.push_back(L'\n');
- line_width=0;
- }
+ line_width=0;
+ }
buff.append(format_string(L"%ls%ls", line_width?L" ":L"", token ));
- free( token );
- line_width += (line_width!=0?1:0) + tok_width;
- }
-
- /*
- Break on end of string
- */
- if( !*pos )
- {
- break;
- }
-
- start=pos;
- }
- }
- else
- {
+ free( token );
+ line_width += (line_width!=0?1:0) + tok_width;
+ }
+
+ /*
+ Break on end of string
+ */
+ if( !*pos )
+ {
+ break;
+ }
+
+ start=pos;
+ }
+ }
+ else
+ {
buff.append(msg);
- }
+ }
buff.push_back(L'\n');
}
@@ -851,198 +851,198 @@ void write_screen( const wcstring &msg, wcstring &buff )
*/
static wchar_t *escape_simple( const wchar_t *in )
{
- wchar_t *out;
- size_t len = wcslen(in);
- out = (wchar_t *)malloc( sizeof(wchar_t)*(len+3));
- if( !out )
- DIE_MEM();
-
- out[0] = L'\'';
- wcscpy(&out[1], in );
- out[len+1]=L'\'';
- out[len+2]=0;
- return out;
+ wchar_t *out;
+ size_t len = wcslen(in);
+ out = (wchar_t *)malloc( sizeof(wchar_t)*(len+3));
+ if( !out )
+ DIE_MEM();
+
+ out[0] = L'\'';
+ wcscpy(&out[1], in );
+ out[len+1]=L'\'';
+ out[len+2]=0;
+ return out;
}
wchar_t *escape( const wchar_t *in_orig, escape_flags_t flags )
{
- const wchar_t *in = in_orig;
-
- bool escape_all = !! (flags & ESCAPE_ALL);
- bool no_quoted = !! (flags & ESCAPE_NO_QUOTED);
+ const wchar_t *in = in_orig;
+
+ bool escape_all = !! (flags & ESCAPE_ALL);
+ bool no_quoted = !! (flags & ESCAPE_NO_QUOTED);
bool no_tilde = !! (flags & ESCAPE_NO_TILDE);
+
+ wchar_t *out;
+ wchar_t *pos;
- wchar_t *out;
- wchar_t *pos;
+ int need_escape=0;
+ int need_complex_escape=0;
- int need_escape=0;
- int need_complex_escape=0;
+ if( !in )
+ {
+ debug( 0, L"%s called with null input", __func__ );
+ FATAL_EXIT();
+ }
- if( !in )
- {
- debug( 0, L"%s called with null input", __func__ );
- FATAL_EXIT();
- }
+ if( !no_quoted && (wcslen( in ) == 0) )
+ {
+ out = wcsdup(L"''");
+ if( !out )
+ DIE_MEM();
+ return out;
+ }
+
+
+ out = (wchar_t *)malloc( sizeof(wchar_t)*(wcslen(in)*4 + 1));
+ pos = out;
+
+ if( !out )
+ DIE_MEM();
+
+ while( *in != 0 )
+ {
- if( !no_quoted && (wcslen( in ) == 0) )
- {
- out = wcsdup(L"''");
- if( !out )
- DIE_MEM();
- return out;
- }
-
-
- out = (wchar_t *)malloc( sizeof(wchar_t)*(wcslen(in)*4 + 1));
- pos = out;
-
- if( !out )
- DIE_MEM();
-
- while( *in != 0 )
- {
-
- if( ( *in >= ENCODE_DIRECT_BASE) &&
- ( *in < ENCODE_DIRECT_BASE+256) )
- {
- int val = *in - ENCODE_DIRECT_BASE;
- int tmp;
-
- *(pos++) = L'\\';
- *(pos++) = L'X';
-
- tmp = val/16;
- *pos++ = tmp > 9? L'a'+(tmp-10):L'0'+tmp;
-
- tmp = val%16;
- *pos++ = tmp > 9? L'a'+(tmp-10):L'0'+tmp;
- need_escape=need_complex_escape=1;
-
- }
- else
- {
+ if( ( *in >= ENCODE_DIRECT_BASE) &&
+ ( *in < ENCODE_DIRECT_BASE+256) )
+ {
+ int val = *in - ENCODE_DIRECT_BASE;
+ int tmp;
+
+ *(pos++) = L'\\';
+ *(pos++) = L'X';
+
+ tmp = val/16;
+ *pos++ = tmp > 9? L'a'+(tmp-10):L'0'+tmp;
+
+ tmp = val%16;
+ *pos++ = tmp > 9? L'a'+(tmp-10):L'0'+tmp;
+ need_escape=need_complex_escape=1;
+
+ }
+ else
+ {
wchar_t c = *in;
- switch( c )
- {
- case L'\t':
- *(pos++) = L'\\';
- *(pos++) = L't';
- need_escape=need_complex_escape=1;
- break;
+ switch( c )
+ {
+ case L'\t':
+ *(pos++) = L'\\';
+ *(pos++) = L't';
+ need_escape=need_complex_escape=1;
+ break;
+
+ case L'\n':
+ *(pos++) = L'\\';
+ *(pos++) = L'n';
+ need_escape=need_complex_escape=1;
+ break;
+
+ case L'\b':
+ *(pos++) = L'\\';
+ *(pos++) = L'b';
+ need_escape=need_complex_escape=1;
+ break;
+
+ case L'\r':
+ *(pos++) = L'\\';
+ *(pos++) = L'r';
+ need_escape=need_complex_escape=1;
+ break;
+
+ case L'\x1b':
+ *(pos++) = L'\\';
+ *(pos++) = L'e';
+ need_escape=need_complex_escape=1;
+ break;
+
- case L'\n':
- *(pos++) = L'\\';
- *(pos++) = L'n';
- need_escape=need_complex_escape=1;
- break;
+ case L'\\':
+ case L'\'':
+ {
+ need_escape=need_complex_escape=1;
+ if( escape_all )
+ *pos++ = L'\\';
+ *pos++ = *in;
+ break;
+ }
- case L'\b':
- *(pos++) = L'\\';
- *(pos++) = L'b';
- need_escape=need_complex_escape=1;
- break;
-
- case L'\r':
- *(pos++) = L'\\';
- *(pos++) = L'r';
- need_escape=need_complex_escape=1;
- break;
-
- case L'\x1b':
- *(pos++) = L'\\';
- *(pos++) = L'e';
- need_escape=need_complex_escape=1;
- break;
-
-
- case L'\\':
- case L'\'':
- {
- need_escape=need_complex_escape=1;
- if( escape_all )
- *pos++ = L'\\';
- *pos++ = *in;
- break;
- }
-
- case L'&':
- case L'$':
- case L' ':
- case L'#':
- case L'^':
- case L'<':
- case L'>':
- case L'(':
- case L')':
- case L'[':
- case L']':
- case L'{':
- case L'}':
- case L'?':
- case L'*':
- case L'|':
- case L';':
- case L'"':
- case L'%':
- case L'~':
- {
+ case L'&':
+ case L'$':
+ case L' ':
+ case L'#':
+ case L'^':
+ case L'<':
+ case L'>':
+ case L'(':
+ case L')':
+ case L'[':
+ case L']':
+ case L'{':
+ case L'}':
+ case L'?':
+ case L'*':
+ case L'|':
+ case L';':
+ case L'"':
+ case L'%':
+ case L'~':
+ {
if (! no_tilde || c != L'~')
{
need_escape=1;
if( escape_all )
*pos++ = L'\\';
}
- *pos++ = *in;
- break;
- }
+ *pos++ = *in;
+ break;
+ }
+
+ default:
+ {
+ if( *in < 32 )
+ {
+ if( *in <27 && *in > 0 )
+ {
+ *(pos++) = L'\\';
+ *(pos++) = L'c';
+ *(pos++) = L'a' + *in -1;
+
+ need_escape=need_complex_escape=1;
+ break;
+
+ }
+
- default:
- {
- if( *in < 32 )
- {
- if( *in <27 && *in > 0 )
- {
- *(pos++) = L'\\';
- *(pos++) = L'c';
- *(pos++) = L'a' + *in -1;
+ int tmp = (*in)%16;
+ *pos++ = L'\\';
+ *pos++ = L'x';
+ *pos++ = ((*in>15)? L'1' : L'0');
+ *pos++ = tmp > 9? L'a'+(tmp-10):L'0'+tmp;
+ need_escape=need_complex_escape=1;
+ }
+ else
+ {
+ *pos++ = *in;
+ }
+ break;
+ }
+ }
+ }
+
+ in++;
+ }
+ *pos = 0;
- need_escape=need_complex_escape=1;
- break;
-
- }
-
-
- int tmp = (*in)%16;
- *pos++ = L'\\';
- *pos++ = L'x';
- *pos++ = ((*in>15)? L'1' : L'0');
- *pos++ = tmp > 9? L'a'+(tmp-10):L'0'+tmp;
- need_escape=need_complex_escape=1;
- }
- else
- {
- *pos++ = *in;
- }
- break;
- }
- }
- }
-
- in++;
- }
- *pos = 0;
-
- /*
- Use quoted escaping if possible, since most people find it
- easier to read.
- */
- if( !no_quoted && need_escape && !need_complex_escape && escape_all )
- {
- free( out );
- out = escape_simple( in_orig );
- }
-
- return out;
+ /*
+ Use quoted escaping if possible, since most people find it
+ easier to read.
+ */
+ if( !no_quoted && need_escape && !need_complex_escape && escape_all )
+ {
+ free( out );
+ out = escape_simple( in_orig );
+ }
+
+ return out;
}
wcstring escape_string( const wcstring &in, escape_flags_t flags ) {
@@ -1054,542 +1054,542 @@ wcstring escape_string( const wcstring &in, escape_flags_t flags ) {
wchar_t *unescape( const wchar_t * orig, int flags )
{
-
- int mode = 0;
+
+ int mode = 0;
int out_pos;
- size_t in_pos;
+ size_t in_pos;
size_t len;
- int c;
- int bracket_count=0;
- wchar_t prev=0;
- wchar_t *in;
- int unescape_special = flags & UNESCAPE_SPECIAL;
- int allow_incomplete = flags & UNESCAPE_INCOMPLETE;
+ int c;
+ int bracket_count=0;
+ wchar_t prev=0;
+ wchar_t *in;
+ int unescape_special = flags & UNESCAPE_SPECIAL;
+ int allow_incomplete = flags & UNESCAPE_INCOMPLETE;
+
+ CHECK( orig, 0 );
+
+ len = wcslen( orig );
+ in = wcsdup( orig );
- CHECK( orig, 0 );
+ if( !in )
+ DIE_MEM();
+
+ for( in_pos=0, out_pos=0;
+ in_pos=0)?in[out_pos]:0), out_pos++, in_pos++ )
+ {
+ c = in[in_pos];
+ switch( mode )
+ {
- len = wcslen( orig );
- in = wcsdup( orig );
-
- if( !in )
- DIE_MEM();
-
- for( in_pos=0, out_pos=0;
- in_pos=0)?in[out_pos]:0), out_pos++, in_pos++ )
- {
- c = in[in_pos];
- switch( mode )
- {
-
- /*
- Mode 0 means unquoted string
- */
- case 0:
- {
- if( c == L'\\' )
- {
- switch( in[++in_pos] )
- {
-
- /*
- A null character after a backslash is an
- error, return null
- */
- case L'\0':
- {
- if( !allow_incomplete )
- {
- free(in);
- return 0;
- }
- }
-
- /*
- Numeric escape sequences. No prefix means
- octal escape, otherwise hexadecimal.
- */
-
- case L'0':
- case L'1':
- case L'2':
- case L'3':
- case L'4':
- case L'5':
- case L'6':
- case L'7':
- case L'u':
- case L'U':
- case L'x':
- case L'X':
- {
- int i;
- long long res=0;
- int chars=2;
- int base=16;
-
- int byte = 0;
- wchar_t max_val = ASCII_MAX;
-
- switch( in[in_pos] )
- {
- case L'u':
- {
- chars=4;
- max_val = UCS2_MAX;
- break;
- }
-
- case L'U':
- {
- chars=8;
- max_val = WCHAR_MAX;
- break;
- }
-
- case L'x':
- {
- break;
- }
-
- case L'X':
- {
- byte=1;
- max_val = BYTE_MAX;
- break;
- }
-
- default:
- {
- base=8;
- chars=3;
+ /*
+ Mode 0 means unquoted string
+ */
+ case 0:
+ {
+ if( c == L'\\' )
+ {
+ switch( in[++in_pos] )
+ {
+
+ /*
+ A null character after a backslash is an
+ error, return null
+ */
+ case L'\0':
+ {
+ if( !allow_incomplete )
+ {
+ free(in);
+ return 0;
+ }
+ }
+
+ /*
+ Numeric escape sequences. No prefix means
+ octal escape, otherwise hexadecimal.
+ */
+
+ case L'0':
+ case L'1':
+ case L'2':
+ case L'3':
+ case L'4':
+ case L'5':
+ case L'6':
+ case L'7':
+ case L'u':
+ case L'U':
+ case L'x':
+ case L'X':
+ {
+ int i;
+ long long res=0;
+ int chars=2;
+ int base=16;
+
+ int byte = 0;
+ wchar_t max_val = ASCII_MAX;
+
+ switch( in[in_pos] )
+ {
+ case L'u':
+ {
+ chars=4;
+ max_val = UCS2_MAX;
+ break;
+ }
+
+ case L'U':
+ {
+ chars=8;
+ max_val = WCHAR_MAX;
+ break;
+ }
+
+ case L'x':
+ {
+ break;
+ }
+
+ case L'X':
+ {
+ byte=1;
+ max_val = BYTE_MAX;
+ break;
+ }
+
+ default:
+ {
+ base=8;
+ chars=3;
// note in_pod must be larger than 0 since we incremented it above
assert(in_pos > 0);
- in_pos--;
- break;
- }
- }
+ in_pos--;
+ break;
+ }
+ }
+
+ for( i=0; i= L'a' &&
+ in[in_pos] <= (L'a'+32) )
+ {
+ in[out_pos]=in[in_pos]-L'a'+1;
+ }
+ else if( in[in_pos] >= L'A' &&
+ in[in_pos] <= (L'A'+32) )
+ {
+ in[out_pos]=in[in_pos]-L'A'+1;
+ }
+ else
+ {
+ free(in);
+ return 0;
+ }
+ break;
+
+ }
+
+ /*
+ \x1b means escape
+ */
+ case L'e':
+ {
+ in[out_pos]=L'\x1b';
+ break;
+ }
+
+ /*
+ \f means form feed
+ */
+ case L'f':
+ {
+ in[out_pos]=L'\f';
+ break;
+ }
- res=(res*base)|d;
- }
+ /*
+ \n means newline
+ */
+ case L'n':
+ {
+ in[out_pos]=L'\n';
+ break;
+ }
+
+ /*
+ \r means carriage return
+ */
+ case L'r':
+ {
+ in[out_pos]=L'\r';
+ break;
+ }
+
+ /*
+ \t means tab
+ */
+ case L't':
+ {
+ in[out_pos]=L'\t';
+ break;
+ }
- if( (res <= max_val) )
- {
- in[out_pos] = (wchar_t)((byte?ENCODE_DIRECT_BASE:0)+res);
- }
- else
- {
- free(in);
- return 0;
- }
+ /*
+ \v means vertical tab
+ */
+ case L'v':
+ {
+ in[out_pos]=L'\v';
+ break;
+ }
+
+ default:
+ {
+ if( unescape_special )
+ in[out_pos++] = INTERNAL_SEPARATOR;
+ in[out_pos]=in[in_pos];
+ break;
+ }
+ }
+ }
+ else
+ {
+ switch( in[in_pos])
+ {
+ case L'~':
+ {
+ if( unescape_special && (in_pos == 0) )
+ {
+ in[out_pos]=HOME_DIRECTORY;
+ }
+ else
+ {
+ in[out_pos] = L'~';
+ }
+ break;
+ }
- break;
- }
+ case L'%':
+ {
+ if( unescape_special && (in_pos == 0) )
+ {
+ in[out_pos]=PROCESS_EXPAND;
+ }
+ else
+ {
+ in[out_pos]=in[in_pos];
+ }
+ break;
+ }
- /*
- \a means bell (alert)
- */
- case L'a':
- {
- in[out_pos]=L'\a';
- break;
- }
+ case L'*':
+ {
+ if( unescape_special )
+ {
+ if( out_pos > 0 && in[out_pos-1]==ANY_STRING )
+ {
+ out_pos--;
+ in[out_pos] = ANY_STRING_RECURSIVE;
+ }
+ else
+ in[out_pos]=ANY_STRING;
+ }
+ else
+ {
+ in[out_pos]=in[in_pos];
+ }
+ break;
+ }
- /*
- \b means backspace
- */
- case L'b':
- {
- in[out_pos]=L'\b';
- break;
- }
+ case L'?':
+ {
+ if( unescape_special )
+ {
+ in[out_pos]=ANY_CHAR;
+ }
+ else
+ {
+ in[out_pos]=in[in_pos];
+ }
+ break;
+ }
- /*
- \cX means control sequence X
- */
- case L'c':
- {
- in_pos++;
- if( in[in_pos] >= L'a' &&
- in[in_pos] <= (L'a'+32) )
- {
- in[out_pos]=in[in_pos]-L'a'+1;
- }
- else if( in[in_pos] >= L'A' &&
- in[in_pos] <= (L'A'+32) )
- {
- in[out_pos]=in[in_pos]-L'A'+1;
- }
- else
- {
- free(in);
- return 0;
- }
- break;
+ case L'$':
+ {
+ if( unescape_special )
+ {
+ in[out_pos]=VARIABLE_EXPAND;
+ }
+ else
+ {
+ in[out_pos]=in[in_pos];
+ }
+ break;
+ }
- }
+ case L'{':
+ {
+ if( unescape_special )
+ {
+ bracket_count++;
+ in[out_pos]=BRACKET_BEGIN;
+ }
+ else
+ {
+ in[out_pos]=in[in_pos];
+ }
+ break;
+ }
+
+ case L'}':
+ {
+ if( unescape_special )
+ {
+ bracket_count--;
+ in[out_pos]=BRACKET_END;
+ }
+ else
+ {
+ in[out_pos]=in[in_pos];
+ }
+ break;
+ }
+
+ case L',':
+ {
+ if( unescape_special && bracket_count && prev!=BRACKET_SEP)
+ {
+ in[out_pos]=BRACKET_SEP;
+ }
+ else
+ {
+ in[out_pos]=in[in_pos];
+ }
+ break;
+ }
+
+ case L'\'':
+ {
+ mode = 1;
+ if( unescape_special )
+ in[out_pos] = INTERNAL_SEPARATOR;
+ else
+ out_pos--;
+ break;
+ }
+
+ case L'\"':
+ {
+ mode = 2;
+ if( unescape_special )
+ in[out_pos] = INTERNAL_SEPARATOR;
+ else
+ out_pos--;
+ break;
+ }
- /*
- \x1b means escape
- */
- case L'e':
- {
- in[out_pos]=L'\x1b';
- break;
- }
+ default:
+ {
+ in[out_pos] = in[in_pos];
+ break;
+ }
+ }
+ }
+ break;
+ }
- /*
- \f means form feed
- */
- case L'f':
- {
- in[out_pos]=L'\f';
- break;
- }
+ /*
+ Mode 1 means single quoted string, i.e 'foo'
+ */
+ case 1:
+ {
+ if( c == L'\\' )
+ {
+ switch( in[++in_pos] )
+ {
+ case '\\':
+ case L'\'':
+ case L'\n':
+ {
+ in[out_pos]=in[in_pos];
+ break;
+ }
+
+ case 0:
+ {
+ if( !allow_incomplete )
+ {
+ free(in);
+ return 0;
+ }
+ else
+ {
+ //We may ever escape a NULL character, but still appending a \ in case I am wrong.
+ in[out_pos] = L'\\';
+ }
+ }
+ break;
+ default:
+ {
+ in[out_pos++] = L'\\';
+ in[out_pos]= in[in_pos];
+ }
+ }
+
+ }
+ if( c == L'\'' )
+ {
+ if( unescape_special )
+ in[out_pos] = INTERNAL_SEPARATOR;
+ else
+ out_pos--;
+ mode = 0;
+ }
+ else
+ {
+ in[out_pos] = in[in_pos];
+ }
+
+ break;
+ }
- /*
- \n means newline
- */
- case L'n':
- {
- in[out_pos]=L'\n';
- break;
- }
+ /*
+ Mode 2 means double quoted string, i.e. "foo"
+ */
+ case 2:
+ {
+ switch( c )
+ {
+ case '"':
+ {
+ mode = 0;
+ if( unescape_special )
+ in[out_pos] = INTERNAL_SEPARATOR;
+ else
+ out_pos--;
+ break;
+ }
+
+ case '\\':
+ {
+ switch( in[++in_pos] )
+ {
+ case L'\0':
+ {
+ if( !allow_incomplete )
+ {
+ free(in);
+ return 0;
+ }
+ else
+ {
+ //We probably don't need it since NULL character is always appended before ending this function.
+ in[out_pos]=in[in_pos];
+ }
+ }
+ break;
+ case '\\':
+ case L'$':
+ case '"':
+ case '\n':
+ {
+ in[out_pos]=in[in_pos];
+ break;
+ }
- /*
- \r means carriage return
- */
- case L'r':
- {
- in[out_pos]=L'\r';
- break;
- }
+ default:
+ {
+ in[out_pos++] = L'\\';
+ in[out_pos] = in[in_pos];
+ break;
+ }
+ }
+ break;
+ }
+
+ case '$':
+ {
+ if( unescape_special )
+ {
+ in[out_pos]=VARIABLE_EXPAND_SINGLE;
+ }
+ else
+ {
+ in[out_pos]=in[in_pos];
+ }
+ break;
+ }
+
+ default:
+ {
+ in[out_pos] = in[in_pos];
+ break;
+ }
+
+ }
+ break;
+ }
+ }
+ }
- /*
- \t means tab
- */
- case L't':
- {
- in[out_pos]=L'\t';
- break;
- }
+ if( !allow_incomplete && mode )
+ {
+ free( in );
+ return 0;
+ }
- /*
- \v means vertical tab
- */
- case L'v':
- {
- in[out_pos]=L'\v';
- break;
- }
-
- default:
- {
- if( unescape_special )
- in[out_pos++] = INTERNAL_SEPARATOR;
- in[out_pos]=in[in_pos];
- break;
- }
- }
- }
- else
- {
- switch( in[in_pos])
- {
- case L'~':
- {
- if( unescape_special && (in_pos == 0) )
- {
- in[out_pos]=HOME_DIRECTORY;
- }
- else
- {
- in[out_pos] = L'~';
- }
- break;
- }
-
- case L'%':
- {
- if( unescape_special && (in_pos == 0) )
- {
- in[out_pos]=PROCESS_EXPAND;
- }
- else
- {
- in[out_pos]=in[in_pos];
- }
- break;
- }
-
- case L'*':
- {
- if( unescape_special )
- {
- if( out_pos > 0 && in[out_pos-1]==ANY_STRING )
- {
- out_pos--;
- in[out_pos] = ANY_STRING_RECURSIVE;
- }
- else
- in[out_pos]=ANY_STRING;
- }
- else
- {
- in[out_pos]=in[in_pos];
- }
- break;
- }
-
- case L'?':
- {
- if( unescape_special )
- {
- in[out_pos]=ANY_CHAR;
- }
- else
- {
- in[out_pos]=in[in_pos];
- }
- break;
- }
-
- case L'$':
- {
- if( unescape_special )
- {
- in[out_pos]=VARIABLE_EXPAND;
- }
- else
- {
- in[out_pos]=in[in_pos];
- }
- break;
- }
-
- case L'{':
- {
- if( unescape_special )
- {
- bracket_count++;
- in[out_pos]=BRACKET_BEGIN;
- }
- else
- {
- in[out_pos]=in[in_pos];
- }
- break;
- }
-
- case L'}':
- {
- if( unescape_special )
- {
- bracket_count--;
- in[out_pos]=BRACKET_END;
- }
- else
- {
- in[out_pos]=in[in_pos];
- }
- break;
- }
-
- case L',':
- {
- if( unescape_special && bracket_count && prev!=BRACKET_SEP)
- {
- in[out_pos]=BRACKET_SEP;
- }
- else
- {
- in[out_pos]=in[in_pos];
- }
- break;
- }
-
- case L'\'':
- {
- mode = 1;
- if( unescape_special )
- in[out_pos] = INTERNAL_SEPARATOR;
- else
- out_pos--;
- break;
- }
-
- case L'\"':
- {
- mode = 2;
- if( unescape_special )
- in[out_pos] = INTERNAL_SEPARATOR;
- else
- out_pos--;
- break;
- }
-
- default:
- {
- in[out_pos] = in[in_pos];
- break;
- }
- }
- }
- break;
- }
-
- /*
- Mode 1 means single quoted string, i.e 'foo'
- */
- case 1:
- {
- if( c == L'\\' )
- {
- switch( in[++in_pos] )
- {
- case '\\':
- case L'\'':
- case L'\n':
- {
- in[out_pos]=in[in_pos];
- break;
- }
-
- case 0:
- {
- if( !allow_incomplete )
- {
- free(in);
- return 0;
- }
- else
- {
- //We may ever escape a NULL character, but still appending a \ in case I am wrong.
- in[out_pos] = L'\\';
- }
- }
- break;
- default:
- {
- in[out_pos++] = L'\\';
- in[out_pos]= in[in_pos];
- }
- }
-
- }
- if( c == L'\'' )
- {
- if( unescape_special )
- in[out_pos] = INTERNAL_SEPARATOR;
- else
- out_pos--;
- mode = 0;
- }
- else
- {
- in[out_pos] = in[in_pos];
- }
-
- break;
- }
-
- /*
- Mode 2 means double quoted string, i.e. "foo"
- */
- case 2:
- {
- switch( c )
- {
- case '"':
- {
- mode = 0;
- if( unescape_special )
- in[out_pos] = INTERNAL_SEPARATOR;
- else
- out_pos--;
- break;
- }
-
- case '\\':
- {
- switch( in[++in_pos] )
- {
- case L'\0':
- {
- if( !allow_incomplete )
- {
- free(in);
- return 0;
- }
- else
- {
- //We probably don't need it since NULL character is always appended before ending this function.
- in[out_pos]=in[in_pos];
- }
- }
- break;
- case '\\':
- case L'$':
- case '"':
- case '\n':
- {
- in[out_pos]=in[in_pos];
- break;
- }
-
- default:
- {
- in[out_pos++] = L'\\';
- in[out_pos] = in[in_pos];
- break;
- }
- }
- break;
- }
-
- case '$':
- {
- if( unescape_special )
- {
- in[out_pos]=VARIABLE_EXPAND_SINGLE;
- }
- else
- {
- in[out_pos]=in[in_pos];
- }
- break;
- }
-
- default:
- {
- in[out_pos] = in[in_pos];
- break;
- }
-
- }
- break;
- }
- }
- }
-
- if( !allow_incomplete && mode )
- {
- free( in );
- return 0;
- }
-
- in[out_pos]=L'\0';
- return in;
+ in[out_pos]=L'\0';
+ return in;
}
bool unescape_string(wcstring &str, int escape_special)
@@ -1609,25 +1609,25 @@ bool unescape_string(wcstring &str, int escape_special)
void common_handle_winch( int signal )
{
#ifdef HAVE_WINSIZE
- if (ioctl(1,TIOCGWINSZ,&termsize)!=0)
- {
- return;
- }
+ if (ioctl(1,TIOCGWINSZ,&termsize)!=0)
+ {
+ return;
+ }
#else
- termsize.ws_col = 80;
- termsize.ws_row = 24;
+ termsize.ws_col = 80;
+ termsize.ws_row = 24;
#endif
}
int common_get_width()
{
- return termsize.ws_col;
+ return termsize.ws_col;
}
int common_get_height()
{
- return termsize.ws_row;
+ return termsize.ws_row;
}
void tokenize_variable_array( const wcstring &val, std::vector &out)
@@ -1677,88 +1677,88 @@ bool list_contains_string(const wcstring_list_t &list, const wcstring &str)
int create_directory( const wcstring &d )
{
- int ok = 0;
- struct stat buf;
- int stat_res = 0;
-
- while( (stat_res = wstat(d, &buf ) ) != 0 )
- {
- if( errno != EAGAIN )
- break;
- }
-
- if( stat_res == 0 )
- {
- if( S_ISDIR( buf.st_mode ) )
- {
- ok = 1;
- }
- }
- else
- {
- if( errno == ENOENT )
- {
+ int ok = 0;
+ struct stat buf;
+ int stat_res = 0;
+
+ while( (stat_res = wstat(d, &buf ) ) != 0 )
+ {
+ if( errno != EAGAIN )
+ break;
+ }
+
+ if( stat_res == 0 )
+ {
+ if( S_ISDIR( buf.st_mode ) )
+ {
+ ok = 1;
+ }
+ }
+ else
+ {
+ if( errno == ENOENT )
+ {
wcstring dir = wdirname(d);
- if( !create_directory( dir ) )
- {
- if( !wmkdir( d, 0700 ) )
- {
- ok = 1;
- }
- }
- }
- }
-
- return ok?0:-1;
+ if( !create_directory( dir ) )
+ {
+ if( !wmkdir( d, 0700 ) )
+ {
+ ok = 1;
+ }
+ }
+ }
+ }
+
+ return ok?0:-1;
}
__attribute__((noinline))
void bugreport()
{
- debug( 1,
- _( L"This is a bug. Break on bugreport to debug."
- L"If you can reproduce it, please send a bug report to %s." ),
- PACKAGE_BUGREPORT );
+ debug( 1,
+ _( L"This is a bug. Break on bugreport to debug."
+ L"If you can reproduce it, please send a bug report to %s." ),
+ PACKAGE_BUGREPORT );
}
wcstring format_size(long long sz)
{
wcstring result;
- const wchar_t *sz_name[]= {
- L"kB", L"MB", L"GB", L"TB", L"PB", L"EB", L"ZB", L"YB", 0
+ const wchar_t *sz_name[]= {
+ L"kB", L"MB", L"GB", L"TB", L"PB", L"EB", L"ZB", L"YB", 0
};
- if( sz < 0 )
- {
- result.append( L"unknown" );
- }
- else if( sz < 1 )
- {
- result.append( _( L"empty" ) );
- }
- else if( sz < 1024 )
- {
- result.append(format_string( L"%lldB", sz ));
- }
- else
- {
- int i;
-
- for( i=0; sz_name[i]; i++ )
- {
- if( sz < (1024*1024) || !sz_name[i+1] )
- {
- long isz = ((long)sz)/1024;
- if( isz > 9 )
- result.append( format_string( L"%d%ls", isz, sz_name[i] ));
- else
- result.append( format_string( L"%.1f%ls", (double)sz/1024, sz_name[i] ));
- break;
- }
- sz /= 1024;
-
- }
- }
+ if( sz < 0 )
+ {
+ result.append( L"unknown" );
+ }
+ else if( sz < 1 )
+ {
+ result.append( _( L"empty" ) );
+ }
+ else if( sz < 1024 )
+ {
+ result.append(format_string( L"%lldB", sz ));
+ }
+ else
+ {
+ int i;
+
+ for( i=0; sz_name[i]; i++ )
+ {
+ if( sz < (1024*1024) || !sz_name[i+1] )
+ {
+ long isz = ((long)sz)/1024;
+ if( isz > 9 )
+ result.append( format_string( L"%d%ls", isz, sz_name[i] ));
+ else
+ result.append( format_string( L"%.1f%ls", (double)sz/1024, sz_name[i] ));
+ break;
+ }
+ sz /= 1024;
+
+ }
+ }
return result;
}
@@ -1793,10 +1793,10 @@ void format_size_safe(char buff[128], unsigned long long sz) {
const size_t max_len = buff_size - 1; //need to leave room for a null terminator
bzero(buff, buff_size);
size_t idx = 0;
- const char * const sz_name[]= {
+ const char * const sz_name[]= {
"kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", NULL
};
- if (sz < 1)
+ if (sz < 1)
{
strncpy(buff, "empty", buff_size);
}
@@ -1807,16 +1807,16 @@ void format_size_safe(char buff[128], unsigned long long sz) {
}
else
{
- for( size_t i=0; sz_name[i]; i++ )
- {
- if( sz < (1024*1024) || !sz_name[i+1] )
- {
- unsigned long long isz = sz/1024;
- if( isz > 9 )
+ for( size_t i=0; sz_name[i]; i++ )
+ {
+ if( sz < (1024*1024) || !sz_name[i+1] )
+ {
+ unsigned long long isz = sz/1024;
+ if( isz > 9 )
{
append_ull(buff, isz, &idx, max_len);
}
- else
+ else
{
if (isz == 0)
{
@@ -1826,7 +1826,7 @@ void format_size_safe(char buff[128], unsigned long long sz) {
{
append_ull(buff, isz, &idx, max_len);
}
-
+
// Maybe append a single fraction digit
unsigned long long remainder = sz % 1024;
if (remainder > 0)
@@ -1836,33 +1836,33 @@ void format_size_safe(char buff[128], unsigned long long sz) {
}
}
append_str(buff, sz_name[i], &idx, max_len);
- break;
- }
- sz /= 1024;
- }
+ break;
+ }
+ sz /= 1024;
+ }
}
}
double timef()
{
- int time_res;
- struct timeval tv;
-
- time_res = gettimeofday(&tv, 0);
-
- if( time_res )
- {
- /*
- Fixme: What on earth is the correct parameter value for NaN?
- The man pages and the standard helpfully state that this
- parameter is implementation defined. Gcc gives a warning if
- a null pointer is used. But not even all mighty Google gives
- a hint to what value should actually be returned.
- */
- return nan("");
- }
-
- return (double)tv.tv_sec + 0.000001*tv.tv_usec;
+ int time_res;
+ struct timeval tv;
+
+ time_res = gettimeofday(&tv, 0);
+
+ if( time_res )
+ {
+ /*
+ Fixme: What on earth is the correct parameter value for NaN?
+ The man pages and the standard helpfully state that this
+ parameter is implementation defined. Gcc gives a warning if
+ a null pointer is used. But not even all mighty Google gives
+ a hint to what value should actually be returned.
+ */
+ return nan("");
+ }
+
+ return (double)tv.tv_sec + 0.000001*tv.tv_usec;
}
void exit_without_destructors(int code) {
@@ -1874,7 +1874,7 @@ null_terminated_array_t convert_wide_array_to_narrow(const null_terminated
const wchar_t *const *arr = wide_arr.get();
if (! arr)
return null_terminated_array_t();
-
+
std::vector list;
for (size_t i=0; arr[i]; i++) {
list.push_back(wcs2string(arr[i]));
@@ -1905,9 +1905,9 @@ extern "C" {
__attribute__((noinline)) void debug_thread_error(void) { while (1) sleep(9999999); }
}
-
+
void set_main_thread() {
- main_thread_id = pthread_self();
+ main_thread_id = pthread_self();
}
void configure_thread_assertions_for_testing(void) {
@@ -1917,10 +1917,13 @@ void configure_thread_assertions_for_testing(void) {
/* Notice when we've forked */
static pid_t initial_pid = 0;
+/* Be able to restore the term's foreground process group */
+static pid_t initial_foreground_process_group = -1;
+
bool is_forked_child(void) {
/* Just bail if nobody's called setup_fork_guards - e.g. fishd */
if (! initial_pid) return false;
-
+
bool is_child_of_fork = (getpid() != initial_pid);
if (is_child_of_fork) {
printf("Uh-oh: %d\n", getpid());
@@ -1929,14 +1932,28 @@ bool is_forked_child(void) {
return is_child_of_fork;
}
-void setup_fork_guards(void) {
+void setup_fork_guards(void)
+{
/* Notice when we fork by stashing our pid. This seems simpler than pthread_atfork(). */
initial_pid = getpid();
}
+void save_term_foreground_process_group(void)
+{
+ initial_foreground_process_group = tcgetpgrp(STDIN_FILENO);
+}
+
+void restore_term_foreground_process_group(void)
+{
+ if (initial_foreground_process_group != -1)
+ {
+ tcsetpgrp(STDIN_FILENO, initial_foreground_process_group);
+ }
+}
+
bool is_main_thread() {
- assert (main_thread_id != 0);
- return main_thread_id == pthread_self();
+ assert (main_thread_id != 0);
+ return main_thread_id == pthread_self();
}
void assert_is_main_thread(const char *who)
@@ -2012,7 +2029,7 @@ bool wcstokenizer::next(wcstring &result) {
if (tmp) result = tmp;
return tmp != NULL;
}
-
+
wcstokenizer::~wcstokenizer() {
free(buffer);
}
diff --git a/common.h b/common.h
index 96e95d32c..9cb574886 100644
--- a/common.h
+++ b/common.h
@@ -1,5 +1,5 @@
/** \file common.h
- Prototypes for various functions, mostly string utilities, that are used by most parts of fish.
+ Prototypes for various functions, mostly string utilities, that are used by most parts of fish.
*/
#ifndef FISH_COMMON_H
@@ -67,10 +67,10 @@ typedef std::vector wcstring_list_t;
enum {
/** Escape all characters, including magic characters like the semicolon */
ESCAPE_ALL = 1 << 0,
-
+
/** Do not try to use 'simplified' quoted escapes, and do not use empty quotes as the empty string */
ESCAPE_NO_QUOTED = 1 << 1,
-
+
/** Do not escape tildes */
ESCAPE_NO_TILDE = 1 << 2
};
@@ -84,10 +84,10 @@ typedef unsigned int escape_flags_t;
/** Exits without invoking destructors (via _exit), useful for code after fork. */
void exit_without_destructors(int code) __attribute__ ((noreturn));
-/**
- Save the shell mode on startup so we can restore them on exit
+/**
+ Save the shell mode on startup so we can restore them on exit
*/
-extern struct termios shell_modes;
+extern struct termios shell_modes;
/**
The character to use where the text has been truncated. Is an
@@ -118,57 +118,57 @@ extern const wchar_t *program_name;
failiure, the current function is ended at once. The second
parameter is the return value of the current function on failiure.
*/
-#define CHECK( arg, retval ) \
- if( !(arg) ) \
- { \
- debug( 0, \
- "function %s called with null value for argument %s. ", \
- __func__, \
- #arg ); \
- bugreport(); \
- show_stackframe(); \
- return retval; \
- }
+#define CHECK( arg, retval ) \
+ if( !(arg) ) \
+ { \
+ debug( 0, \
+ "function %s called with null value for argument %s. ", \
+ __func__, \
+ #arg ); \
+ bugreport(); \
+ show_stackframe(); \
+ return retval; \
+ }
/**
Pause for input, then exit the program. If supported, print a backtrace first.
*/
-#define FATAL_EXIT() \
- { \
- char exit_read_buff; \
- show_stackframe(); \
- read( 0, &exit_read_buff, 1 ); \
- exit_without_destructors( 1 ); \
- } \
-
+#define FATAL_EXIT() \
+ { \
+ char exit_read_buff; \
+ show_stackframe(); \
+ read( 0, &exit_read_buff, 1 ); \
+ exit_without_destructors( 1 ); \
+ } \
+
/**
Exit program at once, leaving an error message about running out of memory.
*/
-#define DIE_MEM() \
- { \
- fwprintf( stderr, \
- L"fish: Out of memory on line %ld of file %s, shutting down fish\n", \
- (long)__LINE__, \
- __FILE__ ); \
- FATAL_EXIT(); \
- }
+#define DIE_MEM() \
+ { \
+ fwprintf( stderr, \
+ L"fish: Out of memory on line %ld of file %s, shutting down fish\n", \
+ (long)__LINE__, \
+ __FILE__ ); \
+ FATAL_EXIT(); \
+ }
/**
Check if signals are blocked. If so, print an error message and
return from the function performing this check.
*/
-#define CHECK_BLOCK( retval ) \
- if( signal_is_blocked() ) \
- { \
- debug( 0, \
- "function %s called while blocking signals. ", \
- __func__); \
- bugreport(); \
- show_stackframe(); \
- return retval; \
- }
-
+#define CHECK_BLOCK( retval ) \
+ if( signal_is_blocked() ) \
+ { \
+ debug( 0, \
+ "function %s called while blocking signals. ", \
+ __func__); \
+ bugreport(); \
+ show_stackframe(); \
+ return retval; \
+ }
+
/**
Shorthand for wgettext call
*/
@@ -176,7 +176,7 @@ extern const wchar_t *program_name;
/**
Noop, used to tell xgettext that a string should be translated,
- even though it is not directly sent to wgettext.
+ even though it is not directly sent to wgettext.
*/
#define N_(wstr) wstr
@@ -192,7 +192,7 @@ void show_stackframe();
/**
- Read a line from the stream f into the string. Returns
+ Read a line from the stream f into the string. Returns
the number of bytes read or -1 on failiure.
If the carriage return character is encountered, it is
@@ -214,7 +214,7 @@ wchar_t *str2wcs( const char *in );
/**
Returns a newly allocated wide character string equivalent of the
specified multibyte character string
-
+
This function encodes illegal character sequences in a reversible
way using the private use area.
*/
@@ -344,7 +344,7 @@ inline wcstring to_string(const int &x) {
template
class null_terminated_array_t {
CharType_t **array;
-
+
typedef std::basic_string string_t;
typedef std::vector string_list_t;
@@ -356,7 +356,7 @@ class null_terminated_array_t {
size_t len;
for (len=0; arr[len] != T(0); len++)
;
- return len;
+ return len;
}
size_t size() const {
@@ -372,24 +372,24 @@ class null_terminated_array_t {
array = NULL;
}
}
-
+
public:
null_terminated_array_t() : array(NULL) { }
null_terminated_array_t(const string_list_t &argv) : array(NULL) { this->set(argv); }
~null_terminated_array_t() { this->free(); }
-
+
/** operator=. Notice the pass-by-value parameter. */
null_terminated_array_t& operator=(null_terminated_array_t rhs) {
if (this != &rhs)
this->swap(rhs);
return *this;
}
-
+
/* Copy constructor. */
null_terminated_array_t(const null_terminated_array_t &him) : array(NULL) {
this->set(him.array);
}
-
+
void set(const string_list_t &argv) {
/* Get rid of the old argv */
this->free();
@@ -405,14 +405,14 @@ class null_terminated_array_t {
}
this->array[count] = NULL;
}
-
+
void set(const CharType_t * const *new_array) {
if (new_array == array)
return;
-
+
/* Get rid of the old argv */
this->free();
-
+
/* Copy the new one */
if (new_array) {
size_t i, count = count_not_null(new_array);
@@ -426,10 +426,10 @@ class null_terminated_array_t {
this->array[count] = NULL;
}
}
-
+
CharType_t **get() { return array; }
const CharType_t * const *get() const { return array; }
-
+
string_list_t to_list() const {
string_list_t lst;
if (array != NULL) {
@@ -448,23 +448,23 @@ null_terminated_array_t convert_wide_array_to_narrow(const null_terminated
class narrow_string_rep_t {
private:
const char *str;
-
+
/* No copying */
narrow_string_rep_t &operator=(const narrow_string_rep_t &);
narrow_string_rep_t(const narrow_string_rep_t &x);
-
+
public:
~narrow_string_rep_t() {
free((void *)str);
}
-
+
narrow_string_rep_t() : str(NULL) {}
-
+
void set(const wcstring &s) {
free((void *)str);
str = wcs2str(s.c_str());
}
-
+
const char *get() const {
return str;
}
@@ -476,7 +476,7 @@ bool is_forked_child();
class scoped_lock {
pthread_mutex_t *lock_obj;
bool locked;
-
+
/* No copying */
scoped_lock &operator=(const scoped_lock &);
scoped_lock(const scoped_lock &);
@@ -492,18 +492,18 @@ public:
class wcstokenizer {
wchar_t *buffer, *str, *state;
const wcstring sep;
-
+
/* No copying */
wcstokenizer &operator=(const wcstokenizer &);
wcstokenizer(const wcstokenizer &);
-
+
public:
wcstokenizer(const wcstring &s, const wcstring &separator);
bool next(wcstring &result);
~wcstokenizer();
};
-/**
+/**
Appends a path component, with a / if necessary
*/
void append_path_component(wcstring &path, const wcstring &component);
@@ -519,7 +519,7 @@ void append_format(wcstring &str, const wchar_t *format, ...);
char **wcsv2strv( const wchar_t * const *in );
/**
- Test if the given string is a valid variable name.
+ Test if the given string is a valid variable name.
\return null if this is a valid name, and a pointer to the first invalid character otherwise
*/
@@ -528,7 +528,7 @@ wchar_t *wcsvarname( const wchar_t *str );
/**
- Test if the given string is a valid function name.
+ Test if the given string is a valid function name.
\return null if this is a valid name, and a pointer to the first invalid character otherwise
*/
@@ -536,7 +536,7 @@ wchar_t *wcsvarname( const wchar_t *str );
const wchar_t *wcsfuncname( const wchar_t *str );
/**
- Test if the given string is valid in a variable name
+ Test if the given string is valid in a variable name
\return 1 if this is a valid name, 0 otherwise
*/
@@ -572,14 +572,14 @@ void error_reset();
This function behaves exactly like a wide character equivalent of
the C function setlocale, except that it will also try to detect if
the user is using a Unicode character set, and if so, use the
- unicode ellipsis character as ellipsis, instead of '$'.
+ unicode ellipsis character as ellipsis, instead of '$'.
*/
wcstring wsetlocale( int category, const wchar_t *locale );
/**
Checks if \c needle is included in the list of strings specified. A warning is printed if needle is zero.
- \param needle the string to search for in the list
+ \param needle the string to search for in the list
\return zero if needle is not found, of if needle is null, non-zero otherwise
*/
@@ -614,9 +614,9 @@ ssize_t read_loop(int fd, void *buff, size_t count);
Because debug is often called to tell the user about an error,
before using wperror to give a specific error message, debug will
never ever modify the value of errno.
-
+
\param level the priority of the message. Lower number means higher priority. Messages with a priority_number higher than \c debug_level will be ignored..
- \param msg the message format string.
+ \param msg the message format string.
Example:
@@ -629,7 +629,7 @@ void debug( int level, const wchar_t *msg, ... );
/**
Replace special characters with backslash escape sequences. Newline is
- replaced with \n, etc.
+ replaced with \n, etc.
\param in The string to be escaped
\param escape_all Whether all characters wich hold special meaning in fish (Pipe, semicolon, etc,) should be escaped, or only unprintable characters
@@ -650,14 +650,14 @@ wcstring escape_string( const wcstring &in, escape_flags_t flags );
an invalid sequence is specified, 0 is returned.
*/
-wchar_t *unescape( const wchar_t * in,
- int escape_special );
+wchar_t *unescape( const wchar_t * in,
+ int escape_special );
-bool unescape_string( wcstring &str,
+bool unescape_string( wcstring &str,
int escape_special );
-/**
+/**
Returns the width of the terminal window, so that not all
functions that use these values continually have to keep track of
it separately.
@@ -688,9 +688,9 @@ void common_handle_winch( int signal );
void write_screen( const wcstring &msg, wcstring &buff );
/**
- Tokenize the specified string into the specified wcstring_list_t.
+ Tokenize the specified string into the specified wcstring_list_t.
\param val the input string. The contents of this string is not changed.
- \param out the list in which to place the elements.
+ \param out the list in which to place the elements.
*/
void tokenize_variable_array( const wcstring &val, wcstring_list_t &out);
@@ -717,7 +717,7 @@ void bugreport();
double timef();
/**
- Call the following function early in main to set the main thread.
+ Call the following function early in main to set the main thread.
This is our replacement for pthread_main_np().
*/
void set_main_thread();
@@ -729,6 +729,10 @@ void configure_thread_assertions_for_testing();
/** Set up a guard to complain if we try to do certain things (like take a lock) after calling fork */
void setup_fork_guards(void);
+/** Save the value of tcgetpgrp so we can restore it on exit */
+void save_term_foreground_process_group(void);
+void restore_term_foreground_process_group(void);
+
/** Return whether we are the child of a fork */
bool is_forked_child(void);
void assert_is_not_forked_child(const char *who);
diff --git a/fish.cpp b/fish.cpp
index 78723bd08..08fc25441 100644
--- a/fish.cpp
+++ b/fish.cpp
@@ -17,7 +17,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file fish.c
- The main loop of fish.
+ The main loop of fish.
*/
#include "config.h"
@@ -104,12 +104,12 @@ static std::string get_executable_path(const char *argv0)
uint32_t buffSize = sizeof buff;
if (0 == _NSGetExecutablePath(buff, &buffSize))
return std::string(buff);
-
+
/* Loop until we're big enough */
char *mbuff = (char *)malloc(buffSize);
while (0 > _NSGetExecutablePath(mbuff, &buffSize))
mbuff = (char *)realloc(mbuff, buffSize);
-
+
/* Return the string */
std::string result = mbuff;
free(mbuff);
@@ -125,7 +125,7 @@ static std::string get_executable_path(const char *argv0)
return std::string(buff);
}
}
-
+
/* Just return argv0, which probably won't work (i.e. it's not an absolute path or a path relative to the working directory, but instead something the caller found via $PATH). We'll eventually fall back to the compile time paths. */
return std::string(argv0 ? argv0 : "");
}
@@ -137,9 +137,9 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
bool done = false;
std::string exec_path = get_executable_path(argv0);
if (get_realpath(exec_path))
- {
+ {
#if __APPLE__
-
+
/* On OS X, maybe we're an app bundle, and should use the bundle's files. Since we don't link CF, use this lame approach to test it: see if the resolved path ends with /Contents/MacOS/fish, case insensitive since HFS+ usually is.
*/
if (! done)
@@ -152,28 +152,28 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
wcstring wide_resolved_path = str2wcstring(exec_path);
wide_resolved_path.resize(exec_path.size() - suffixlen);
wide_resolved_path.append(L"/Contents/Resources/");
-
+
/* Append share, etc, doc */
paths.data = wide_resolved_path + L"share/fish";
paths.sysconf = wide_resolved_path + L"etc/fish";
paths.doc = wide_resolved_path + L"doc/fish";
-
+
/* But the bin_dir is the resolved_path, minus fish (aka the MacOS directory) */
paths.bin = str2wcstring(exec_path);
paths.bin.resize(paths.bin.size() - strlen("/fish"));
-
+
done = true;
}
}
#endif
-
+
if (! done)
{
/* The next check is that we are in a reloctable directory tree like this:
bin/fish
etc/fish
share/fish
-
+
Check it!
*/
const char *suffix = "/bin/fish";
@@ -181,12 +181,12 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
{
wcstring base_path = str2wcstring(exec_path);
base_path.resize(base_path.size() - strlen(suffix));
-
+
paths.data = base_path + L"/share/fish";
paths.sysconf = base_path + L"/etc/fish";
paths.doc = base_path + L"/share/doc/fish";
paths.bin = base_path + L"/bin";
-
+
struct stat buf;
if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf))
{
@@ -195,7 +195,7 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
}
}
}
-
+
if (! done)
{
/* Fall back to what got compiled in. */
@@ -203,10 +203,10 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
paths.sysconf = L"" SYSCONFDIR "/fish";
paths.doc = L"" DATADIR "/doc/fish";
paths.bin = L"" PREFIX "/bin";
-
+
done = true;
}
-
+
return paths;
}
@@ -217,27 +217,27 @@ static int read_init(const struct config_paths_t &paths)
{
parser_t &parser = parser_t::principal_parser();
const io_chain_t empty_ios;
- parser.eval( L"builtin . " + paths.data + L"/config.fish 2>/dev/null", empty_ios, TOP );
- parser.eval( L"builtin . " + paths.sysconf + L"/config.fish 2>/dev/null", empty_ios, TOP );
+ parser.eval( L"builtin . " + paths.data + L"/config.fish 2>/dev/null", empty_ios, TOP );
+ parser.eval( L"builtin . " + paths.sysconf + L"/config.fish 2>/dev/null", empty_ios, TOP );
+
+ /*
+ We need to get the configuration directory before we can source the user configuration file
+ */
+ wcstring config_dir;
- /*
- We need to get the configuration directory before we can source the user configuration file
- */
- wcstring config_dir;
-
- /*
- If path_get_config returns false then we have no configuration directory
- and no custom config to load.
- */
+ /*
+ If path_get_config returns false then we have no configuration directory
+ and no custom config to load.
+ */
if (path_get_config(config_dir))
- {
- wcstring config_dir_escaped = escape_string( config_dir, 1 );
+ {
+ wcstring config_dir_escaped = escape_string( config_dir, 1 );
wcstring eval_buff = format_string(L"builtin . %ls/config.fish 2>/dev/null", config_dir_escaped.c_str());
- parser.eval( eval_buff, empty_ios, TOP );
- }
-
- return 1;
+ parser.eval( eval_buff, empty_ios, TOP );
+ }
+
+ return 1;
}
@@ -247,162 +247,162 @@ static int read_init(const struct config_paths_t &paths)
*/
static int fish_parse_opt( int argc, char **argv, const char **cmd_ptr )
{
- int my_optind;
- int force_interactive=0;
+ int my_optind;
+ int force_interactive=0;
+
+ while( 1 )
+ {
+ static struct option
+ long_options[] =
+ {
+ {
+ "command", required_argument, 0, 'c'
+ }
+ ,
+ {
+ "debug-level", required_argument, 0, 'd'
+ }
+ ,
+ {
+ "interactive", no_argument, 0, 'i'
+ }
+ ,
+ {
+ "login", no_argument, 0, 'l'
+ }
+ ,
+ {
+ "no-execute", no_argument, 0, 'n'
+ }
+ ,
+ {
+ "profile", required_argument, 0, 'p'
+ }
+ ,
+ {
+ "help", no_argument, 0, 'h'
+ }
+ ,
+ {
+ "version", no_argument, 0, 'v'
+ }
+ ,
+ {
+ 0, 0, 0, 0
+ }
+ }
+ ;
+
+ int opt_index = 0;
+
+ int opt = getopt_long( argc,
+ argv,
+ GETOPT_STRING,
+ long_options,
+ &opt_index );
+
+ if( opt == -1 )
+ break;
+
+ switch( opt )
+ {
+ case 0:
+ {
+ break;
+ }
+
+ case 'c':
+ {
+ *cmd_ptr = optarg;
+ is_interactive_session = 0;
+ break;
+ }
+
+ case 'd':
+ {
+ char *end;
+ long tmp;
- while( 1 )
- {
- static struct option
- long_options[] =
- {
- {
- "command", required_argument, 0, 'c'
- }
- ,
- {
- "debug-level", required_argument, 0, 'd'
- }
- ,
- {
- "interactive", no_argument, 0, 'i'
- }
- ,
- {
- "login", no_argument, 0, 'l'
- }
- ,
- {
- "no-execute", no_argument, 0, 'n'
- }
- ,
- {
- "profile", required_argument, 0, 'p'
- }
- ,
- {
- "help", no_argument, 0, 'h'
- }
- ,
- {
- "version", no_argument, 0, 'v'
- }
- ,
- {
- 0, 0, 0, 0
- }
- }
- ;
+ errno = 0;
+ tmp = strtol(optarg, &end, 10);
+
+ if( tmp >= 0 && tmp <=10 && !*end && !errno )
+ {
+ debug_level = (int)tmp;
+ }
+ else
+ {
+ debug( 0, _(L"Invalid value '%s' for debug level switch"), optarg );
+ exit_without_destructors(1);
+ }
+ break;
+ }
+
+ case 'h':
+ {
+ *cmd_ptr = "__fish_print_help fish";
+ break;
+ }
+
+ case 'i':
+ {
+ force_interactive = 1;
+ break;
+ }
+
+ case 'l':
+ {
+ is_login=1;
+ break;
+ }
+
+ case 'n':
+ {
+ no_exec=1;
+ break;
+ }
+
+ case 'p':
+ {
+ profile = optarg;
+ break;
+ }
+
+ case 'v':
+ {
+ fwprintf( stderr,
+ _(L"%s, version %s\n"),
+ PACKAGE_NAME,
+ PACKAGE_VERSION );
+ exit_without_destructors( 0 );
+ }
+
+ case '?':
+ {
+ exit_without_destructors( 1 );
+ }
+
+ }
+ }
- int opt_index = 0;
+ my_optind = optind;
+
+ is_login |= (strcmp( argv[0], "-fish") == 0);
+
+ /*
+ We are an interactive session if we have not been given an
+ explicit command to execute, _and_ stdin is a tty.
+ */
+ is_interactive_session &= (*cmd_ptr == 0);
+ is_interactive_session &= (my_optind == argc);
+ is_interactive_session &= isatty(STDIN_FILENO);
- int opt = getopt_long( argc,
- argv,
- GETOPT_STRING,
- long_options,
- &opt_index );
+ /*
+ We are also an interactive session if we have are forced-
+ */
+ is_interactive_session |= force_interactive;
- if( opt == -1 )
- break;
-
- switch( opt )
- {
- case 0:
- {
- break;
- }
-
- case 'c':
- {
- *cmd_ptr = optarg;
- is_interactive_session = 0;
- break;
- }
-
- case 'd':
- {
- char *end;
- long tmp;
-
- errno = 0;
- tmp = strtol(optarg, &end, 10);
-
- if( tmp >= 0 && tmp <=10 && !*end && !errno )
- {
- debug_level = (int)tmp;
- }
- else
- {
- debug( 0, _(L"Invalid value '%s' for debug level switch"), optarg );
- exit_without_destructors(1);
- }
- break;
- }
-
- case 'h':
- {
- *cmd_ptr = "__fish_print_help fish";
- break;
- }
-
- case 'i':
- {
- force_interactive = 1;
- break;
- }
-
- case 'l':
- {
- is_login=1;
- break;
- }
-
- case 'n':
- {
- no_exec=1;
- break;
- }
-
- case 'p':
- {
- profile = optarg;
- break;
- }
-
- case 'v':
- {
- fwprintf( stderr,
- _(L"%s, version %s\n"),
- PACKAGE_NAME,
- PACKAGE_VERSION );
- exit_without_destructors( 0 );
- }
-
- case '?':
- {
- exit_without_destructors( 1 );
- }
-
- }
- }
-
- my_optind = optind;
-
- is_login |= (strcmp( argv[0], "-fish") == 0);
-
- /*
- We are an interactive session if we have not been given an
- explicit command to execute, _and_ stdin is a tty.
- */
- is_interactive_session &= (*cmd_ptr == 0);
- is_interactive_session &= (my_optind == argc);
- is_interactive_session &= isatty(STDIN_FILENO);
-
- /*
- We are also an interactive session if we have are forced-
- */
- is_interactive_session |= force_interactive;
-
- return my_optind;
+ return my_optind;
}
/**
@@ -412,68 +412,68 @@ static int fish_parse_opt( int argc, char **argv, const char **cmd_ptr )
static wcstring full_escape( const wchar_t *in )
{
- wcstring out;
- for( ; *in; in++ )
- {
- if( *in < 32 )
- {
- append_format( out, L"\\x%.2x", *in );
- }
- else if( *in < 128 )
- {
- out.push_back(*in);
- }
- else if( *in < 65536 )
- {
- append_format( out, L"\\u%.4x", *in );
- }
- else
- {
- append_format( out, L"\\U%.8x", *in );
- }
- }
- return out;
+ wcstring out;
+ for( ; *in; in++ )
+ {
+ if( *in < 32 )
+ {
+ append_format( out, L"\\x%.2x", *in );
+ }
+ else if( *in < 128 )
+ {
+ out.push_back(*in);
+ }
+ else if( *in < 65536 )
+ {
+ append_format( out, L"\\u%.4x", *in );
+ }
+ else
+ {
+ append_format( out, L"\\U%.8x", *in );
+ }
+ }
+ return out;
}
extern int g_fork_count;
int main( int argc, char **argv )
-{
- int res=1;
- const char *cmd=0;
- int my_optind=0;
+{
+ int res=1;
+ const char *cmd=0;
+ int my_optind=0;
- set_main_thread();
+ set_main_thread();
setup_fork_guards();
-
- wsetlocale( LC_ALL, L"" );
- is_interactive_session=1;
- program_name=L"fish";
+ save_term_foreground_process_group();
+
+ wsetlocale( LC_ALL, L"" );
+ is_interactive_session=1;
+ program_name=L"fish";
//struct stat tmp;
//stat("----------FISH_HIT_MAIN----------", &tmp);
- my_optind = fish_parse_opt( argc, argv, &cmd );
+ my_optind = fish_parse_opt( argc, argv, &cmd );
- /*
- No-exec is prohibited when in interactive mode
- */
- if( is_interactive_session && no_exec)
- {
- debug( 1, _(L"Can not use the no-execute mode when running an interactive session") );
- no_exec = 0;
- }
-
- const struct config_paths_t paths = determine_config_directory_paths(argv[0]);
-
- proc_init();
- event_init();
- wutil_init();
- //parser_init();
- builtin_init();
- function_init();
- env_init(&paths);
- reader_init();
- history_init();
+ /*
+ No-exec is prohibited when in interactive mode
+ */
+ if( is_interactive_session && no_exec)
+ {
+ debug( 1, _(L"Can not use the no-execute mode when running an interactive session") );
+ no_exec = 0;
+ }
+
+ const struct config_paths_t paths = determine_config_directory_paths(argv[0]);
+
+ proc_init();
+ event_init();
+ wutil_init();
+ builtin_init();
+ function_init();
+ env_init(&paths);
+ reader_init();
+ history_init();
parser_t &parser = parser_t::principal_parser();
@@ -481,91 +481,92 @@ int main( int argc, char **argv )
printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
const io_chain_t empty_ios;
- if( read_init(paths) )
- {
- if( cmd != 0 )
- {
- wchar_t *cmd_wcs = str2wcs( cmd );
- res = parser.eval( cmd_wcs, empty_ios, TOP );
- free(cmd_wcs);
- reader_exit(0, 0);
- }
- else
- {
- if( my_optind == argc )
- {
- res = reader_read( STDIN_FILENO, empty_ios );
- }
- else
- {
- char **ptr;
- char *file = *(argv+(my_optind++));
- int i;
- int fd;
- wchar_t *rel_filename, *abs_filename;
-
-
- if( ( fd = open(file, O_RDONLY) ) == -1 )
- {
- wperror( L"open" );
- return 1;
- }
+ if( read_init(paths) )
+ {
+ if( cmd != 0 )
+ {
+ wchar_t *cmd_wcs = str2wcs( cmd );
+ res = parser.eval( cmd_wcs, empty_ios, TOP );
+ free(cmd_wcs);
+ reader_exit(0, 0);
+ }
+ else
+ {
+ if( my_optind == argc )
+ {
+ res = reader_read( STDIN_FILENO, empty_ios );
+ }
+ else
+ {
+ char **ptr;
+ char *file = *(argv+(my_optind++));
+ int i;
+ int fd;
+ wchar_t *rel_filename, *abs_filename;
+
+ if( ( fd = open(file, O_RDONLY) ) == -1 )
+ {
+ wperror( L"open" );
+ return 1;
+ }
+
// OK to not do this atomically since we cannot have gone multithreaded yet
set_cloexec(fd);
-
- if( *(argv+my_optind))
- {
+
+ if( *(argv+my_optind))
+ {
wcstring sb;
- for( i=1,ptr = argv+my_optind; *ptr; i++, ptr++ )
- {
- if( i != 1 )
+ for( i=1,ptr = argv+my_optind; *ptr; i++, ptr++ )
+ {
+ if( i != 1 )
sb.append( ARRAY_SEP_STR );
sb.append( str2wcstring( *ptr ));
- }
+ }
+
+ env_set( L"argv", sb.c_str(), 0 );
+ }
- env_set( L"argv", sb.c_str(), 0 );
- }
+ rel_filename = str2wcs( file );
+ abs_filename = wrealpath( rel_filename, 0 );
- rel_filename = str2wcs( file );
- abs_filename = wrealpath( rel_filename, 0 );
+ if( !abs_filename )
+ {
+ abs_filename = wcsdup(rel_filename);
+ }
- if( !abs_filename )
- {
- abs_filename = wcsdup(rel_filename);
- }
+ reader_push_current_filename( intern( abs_filename ) );
+ free( rel_filename );
+ free( abs_filename );
- reader_push_current_filename( intern( abs_filename ) );
- free( rel_filename );
- free( abs_filename );
-
- res = reader_read( fd, empty_ios );
-
- if( res )
- {
- debug( 1,
- _(L"Error while reading file %ls\n"),
- reader_current_filename()?reader_current_filename(): _(L"Standard input") );
- }
- reader_pop_current_filename();
- }
- }
- }
-
- proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res );
-
- history_destroy();
- proc_destroy();
- builtin_destroy();
- reader_destroy();
- parser.destroy();
- wutil_destroy();
- event_destroy();
-
- env_destroy();
+ res = reader_read( fd, empty_ios );
+ if( res )
+ {
+ debug( 1,
+ _(L"Error while reading file %ls\n"),
+ reader_current_filename()?reader_current_filename(): _(L"Standard input") );
+ }
+ reader_pop_current_filename();
+ }
+ }
+ }
+
+ proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res );
+
+ restore_term_foreground_process_group();
+ history_destroy();
+ proc_destroy();
+ builtin_destroy();
+ reader_destroy();
+ parser.destroy();
+ wutil_destroy();
+ event_destroy();
+
+ env_destroy();
+
if (g_log_forks)
printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
-
- return res?STATUS_UNKNOWN_COMMAND:proc_get_last_status();
+
+ return res?STATUS_UNKNOWN_COMMAND:proc_get_last_status();
}
diff --git a/proc.cpp b/proc.cpp
index 0ba13c6cd..7e6cb1a1f 100644
--- a/proc.cpp
+++ b/proc.cpp
@@ -7,7 +7,7 @@ will call proc to create representations of the running jobs as
needed.
Some of the code in this file is based on code from the Glibc manual.
-
+
*/
#include "config.h"
@@ -75,7 +75,7 @@ Some of the code in this file is based on code from the Glibc manual.
#include "output.h"
/**
- Size of message buffer
+ Size of message buffer
*/
#define MESS_SIZE 256
@@ -84,13 +84,13 @@ Some of the code in this file is based on code from the Glibc manual.
*/
#define BUFFER_SIZE 4096
-/**
- Status of last process to exit
+/**
+ Status of last process to exit
*/
static int last_status=0;
/**
- Signal flag
+ Signal flag
*/
static sig_atomic_t got_signal=0;
@@ -156,13 +156,13 @@ static std::vector interactive_stack;
void proc_init()
{
- proc_push_interactive( 0 );
+ proc_push_interactive( 0 );
event.arguments.reset(new wcstring_list_t);
}
/**
- Remove job from list of jobs
+ Remove job from list of jobs
*/
static int job_remove( job_t *j )
{
@@ -183,7 +183,7 @@ void job_promote(job_t *job)
*/
void job_free( job_t * j )
{
- job_remove( j );
+ job_remove( j );
delete j;
}
@@ -191,22 +191,22 @@ void proc_destroy()
{
event.arguments.reset(NULL);
job_list_t &jobs = parser_t::principal_parser().job_list();
- while( ! jobs.empty() )
- {
- job_t *job = jobs.front();
- debug( 2, L"freeing leaked job %ls", job->command_wcstr() );
- job_free( job );
- }
+ while( ! jobs.empty() )
+ {
+ job_t *job = jobs.front();
+ debug( 2, L"freeing leaked job %ls", job->command_wcstr() );
+ job_free( job );
+ }
}
void proc_set_last_status( int s )
{
- last_status = s;
+ last_status = s;
}
int proc_get_last_status()
{
- return last_status;
+ return last_status;
}
/* Basic thread safe job IDs. The vector consumed_job_ids has a true value wherever the job ID corresponding to that slot is in use. The job ID corresponding to slot 0 is 1. */
@@ -216,7 +216,7 @@ static std::vector consumed_job_ids;
job_id_t acquire_job_id(void)
{
scoped_lock lock(job_id_lock);
-
+
/* Find the index of the first 0 slot */
std::vector::iterator slot = std::find(consumed_job_ids.begin(), consumed_job_ids.end(), false);
if (slot != consumed_job_ids.end())
@@ -238,11 +238,11 @@ void release_job_id(job_id_t jid)
assert(jid > 0);
scoped_lock lock(job_id_lock);
size_t slot = (size_t)(jid - 1), count = consumed_job_ids.size();
-
+
/* Make sure this slot is within our vector and is currently set to consumed */
assert(slot < count);
assert(consumed_job_ids.at(slot) == true);
-
+
/* Clear it and then resize the vector to eliminate unused trailing job IDs */
consumed_job_ids.at(slot) = false;
while (count--) {
@@ -265,127 +265,128 @@ job_t *job_get_from_pid( int pid )
}
-/*
- Return true if all processes in the job have stopped or completed.
+/*
+ Return true if all processes in the job have stopped or completed.
\param j the job to test
*/
int job_is_stopped( const job_t *j )
{
- process_t *p;
+ process_t *p;
- for (p = j->first_process; p; p = p->next)
- {
- if (!p->completed && !p->stopped)
- {
- return 0;
- }
- }
- return 1;
+ for (p = j->first_process; p; p = p->next)
+ {
+ if (!p->completed && !p->stopped)
+ {
+ return 0;
+ }
+ }
+ return 1;
}
-/*
- Return true if the last processes in the job has completed.
+/*
+ Return true if the last processes in the job has completed.
\param j the job to test
*/
int job_is_completed( const job_t *j )
{
- process_t *p;
- assert(j->first_process != NULL);
- for (p = j->first_process; p->next; p = p->next)
- ;
-
- return p->completed;
-
+ process_t *p;
+ assert(j->first_process != NULL);
+ for (p = j->first_process; p->next; p = p->next)
+ ;
+
+ return p->completed;
+
}
void job_set_flag( job_t *j, int flag, int set )
{
- if( set )
- j->flags |= flag;
- else
- j->flags = j->flags & ((unsigned int)(-1) ^ flag);
+ if( set )
+ j->flags |= flag;
+ else
+ j->flags = j->flags & ((unsigned int)(-1) ^ flag);
}
int job_get_flag( const job_t *j, int flag )
{
- return j->flags&flag?1:0;
+ return j->flags&flag?1:0;
}
int job_signal( job_t *j, int signal )
-{
- pid_t my_pid = getpid();
- int res = 0;
+{
+ pid_t my_pid = getpid();
+ int res = 0;
+
+ if( j->pgid != my_pid )
+ {
+ res = killpg( j->pgid, SIGHUP );
+ }
+ else
+ {
+ process_t *p;
- if( j->pgid != my_pid )
- {
- res = killpg( j->pgid, SIGHUP );
- }
- else
- {
- process_t *p;
+ for( p = j->first_process; p; p=p->next )
+ {
+ if( ! p->completed )
+ {
+ if( p->pid )
+ {
+ if( kill( p->pid, SIGHUP ) )
+ {
+ res = -1;
+ break;
+ }
+ }
+ }
+ }
- for( p = j->first_process; p; p=p->next )
- {
- if( ! p->completed )
- {
- if( p->pid )
- {
- if( kill( p->pid, SIGHUP ) )
- {
- res = -1;
- break;
- }
- }
- }
- }
+ }
- }
-
- return res;
+ return res;
}
/**
Store the status of the process pid that was returned by waitpid.
- Return 0 if all went well, nonzero otherwise.
+ Return 0 if all went well, nonzero otherwise.
+ This is called from a signal handler.
*/
static void mark_process_status( const job_t *j,
- process_t *p,
- int status )
+ process_t *p,
+ int status )
{
-// debug( 0, L"Process %ls %ls", p->argv[0], WIFSTOPPED (status)?L"stopped":(WIFEXITED( status )?L"exited":(WIFSIGNALED( status )?L"signaled to exit":L"BLARGH")) );
- p->status = status;
+// debug( 0, L"Process %ls %ls", p->argv[0], WIFSTOPPED (status)?L"stopped":(WIFEXITED( status )?L"exited":(WIFSIGNALED( status )?L"signaled to exit":L"BLARGH")) );
+ p->status = status;
+
+ if (WIFSTOPPED (status))
+ {
+ p->stopped = 1;
+ }
+ else if (WIFSIGNALED(status) || WIFEXITED(status))
+ {
+ p->completed = 1;
+ }
+ else
+ {
+ ssize_t ignore;
+
+ /* This should never be reached */
+ p->completed = 1;
- if (WIFSTOPPED (status))
- {
- p->stopped = 1;
- }
- else if (WIFSIGNALED(status) || WIFEXITED(status))
- {
- p->completed = 1;
- }
- else
- {
- ssize_t ignore;
-
- /* This should never be reached */
- p->completed = 1;
-
- char mess[MESS_SIZE];
- snprintf( mess,
- MESS_SIZE,
- "Process %ld exited abnormally\n",
- (long) p->pid );
- /*
- If write fails, do nothing. We're in a signal handlers error
- handler. If things aren't working properly, it's safer to
- give up.
- */
- ignore = write( 2, mess, strlen(mess) );
- }
+ char mess[MESS_SIZE];
+ snprintf( mess,
+ MESS_SIZE,
+ "Process %ld exited abnormally\n",
+ (long) p->pid );
+ /*
+ If write fails, do nothing. We're in a signal handlers error
+ handler. If things aren't working properly, it's safer to
+ give up.
+ */
+ ignore = write( 2, mess, strlen(mess) );
+ }
}
void job_mark_process_as_failed( const job_t *job, process_t *p )
@@ -404,97 +405,97 @@ void job_mark_process_as_failed( const job_t *job, process_t *p )
*/
static void handle_child_status( pid_t pid, int status )
{
- bool found_proc = false;
- const job_t *j=0;
- process_t *p=0;
-// char mess[MESS_SIZE];
- /*
- snprintf( mess,
- MESS_SIZE,
- "Process %d\n",
- (int) pid );
- write( 2, mess, strlen(mess ));
- */
+ bool found_proc = false;
+ const job_t *j=0;
+ process_t *p=0;
+// char mess[MESS_SIZE];
+ /*
+ snprintf( mess,
+ MESS_SIZE,
+ "Process %d\n",
+ (int) pid );
+ write( 2, mess, strlen(mess ));
+ */
job_iterator_t jobs;
- while (! found_proc && (j = jobs.next()))
- {
- process_t *prev=0;
- for( p=j->first_process; p; p=p->next )
- {
- if( pid == p->pid )
- {
-/* snprintf( mess,
+ while (! found_proc && (j = jobs.next()))
+ {
+ process_t *prev=0;
+ for( p=j->first_process; p; p=p->next )
+ {
+ if( pid == p->pid )
+ {
+/* snprintf( mess,
MESS_SIZE,
"Process %d is %ls from job %ls\n",
(int) pid, p->actual_cmd, j->command );
write( 2, mess, strlen(mess ));
-*/
-
- mark_process_status ( j, p, status);
- if( p->completed && prev != 0 )
- {
- if( !prev->completed && prev->pid)
- {
- /* snprintf( mess,
- MESS_SIZE,
- "Kill previously uncompleted process %ls (%d)\n",
- prev->actual_cmd,
- prev->pid );
- write( 2, mess, strlen(mess ));
- */
- kill(prev->pid,SIGPIPE);
- }
- }
- found_proc = true;
- break;
- }
- prev = p;
- }
- }
+*/
+
+ mark_process_status ( j, p, status);
+ if( p->completed && prev != 0 )
+ {
+ if( !prev->completed && prev->pid)
+ {
+ /* snprintf( mess,
+ MESS_SIZE,
+ "Kill previously uncompleted process %ls (%d)\n",
+ prev->actual_cmd,
+ prev->pid );
+ write( 2, mess, strlen(mess ));
+ */
+ kill(prev->pid,SIGPIPE);
+ }
+ }
+ found_proc = true;
+ break;
+ }
+ prev = p;
+ }
+ }
- if( WIFSIGNALED( status ) &&
- ( WTERMSIG(status)==SIGINT ||
- WTERMSIG(status)==SIGQUIT ) )
- {
- if( !is_interactive_session )
- {
- struct sigaction act;
- sigemptyset( & act.sa_mask );
- act.sa_flags=0;
- act.sa_handler=SIG_DFL;
- sigaction( SIGINT, &act, 0 );
- sigaction( SIGQUIT, &act, 0 );
- kill( getpid(), WTERMSIG(status) );
- }
- else
- {
+ if( WIFSIGNALED( status ) &&
+ ( WTERMSIG(status)==SIGINT ||
+ WTERMSIG(status)==SIGQUIT ) )
+ {
+ if( !is_interactive_session )
+ {
+ struct sigaction act;
+ sigemptyset( & act.sa_mask );
+ act.sa_flags=0;
+ act.sa_handler=SIG_DFL;
+ sigaction( SIGINT, &act, 0 );
+ sigaction( SIGQUIT, &act, 0 );
+ kill( getpid(), WTERMSIG(status) );
+ }
+ else
+ {
/* In an interactive session, tell the principal parser to skip all blocks we're executing so control-C returns control to the user. */
- if( p && found_proc )
- {
+ if( p && found_proc )
+ {
parser_t::skip_all_blocks();
- }
- }
- }
-
- if( !found_proc )
- {
- /*
- A child we lost track of?
-
- There have been bugs in both subshell handling and in
- builtin handling that have caused this previously...
- */
-/* snprintf( mess,
+ }
+ }
+ }
+
+ if( !found_proc )
+ {
+ /*
+ A child we lost track of?
+
+ There have been bugs in both subshell handling and in
+ builtin handling that have caused this previously...
+ */
+/* snprintf( mess,
MESS_SIZE,
"Process %d not found by %d\n",
(int) pid, (int)getpid() );
write( 2, mess, strlen(mess ));
*/
- }
- return;
+ }
+ return;
}
process_t::process_t() :
@@ -516,7 +517,7 @@ process_t::process_t() :
#endif
{
}
-
+
process_t::~process_t()
{
if (this->next != NULL)
@@ -534,7 +535,7 @@ job_t::job_t(job_id_t jobid) :
flags(0)
{
}
-
+
job_t::~job_t()
{
if (first_process != NULL)
@@ -546,191 +547,191 @@ job_t::~job_t()
/* This is called from a signal handler */
void job_handle_signal ( int signal, siginfo_t *info, void *con )
{
+
+ int status;
+ pid_t pid;
+ int errno_old = errno;
- int status;
- pid_t pid;
- int errno_old = errno;
+ got_signal = 1;
- got_signal = 1;
+// write( 2, "got signal\n", 11 );
-// write( 2, "got signal\n", 11 );
+ while(1)
+ {
+ switch(pid=waitpid( -1,&status,WUNTRACED|WNOHANG ))
+ {
+ case 0:
+ case -1:
+ {
+ errno=errno_old;
+ return;
+ }
+ default:
- while(1)
- {
- switch(pid=waitpid( -1,&status,WUNTRACED|WNOHANG ))
- {
- case 0:
- case -1:
- {
- errno=errno_old;
- return;
- }
- default:
-
- handle_child_status( pid, status );
- break;
- }
- }
- kill( 0, SIGIO );
- errno=errno_old;
+ handle_child_status( pid, status );
+ break;
+ }
+ }
+ kill( 0, SIGIO );
+ errno=errno_old;
}
-/**
- Format information about job status for the user to look at.
+/**
+ Format information about job status for the user to look at.
- \param j the job to test
- \param status a string description of the job exit type
+ \param j the job to test
+ \param status a string description of the job exit type
*/
static void format_job_info( const job_t *j, const wchar_t *status )
{
- fwprintf (stdout, L"\r" );
- fwprintf (stdout, _( L"Job %d, \'%ls\' has %ls" ), j->job_id, j->command_wcstr(), status);
- fflush( stdout );
- tputs(clr_eol,1,&writeb);
- fwprintf (stdout, L"\n" );
+ fwprintf (stdout, L"\r" );
+ fwprintf (stdout, _( L"Job %d, \'%ls\' has %ls" ), j->job_id, j->command_wcstr(), status);
+ fflush( stdout );
+ tputs(clr_eol,1,&writeb);
+ fwprintf (stdout, L"\n" );
}
void proc_fire_event( const wchar_t *msg, int type, pid_t pid, int status )
{
-
- event.type=type;
- event.param1.pid = pid;
-
+
+ event.type=type;
+ event.param1.pid = pid;
+
event.arguments->push_back(msg);
event.arguments->push_back(to_string(pid));
event.arguments->push_back(to_string(status));
- event_fire( &event );
+ event_fire( &event );
event.arguments->resize(0);
-}
+}
int job_reap( bool interactive )
{
ASSERT_IS_MAIN_THREAD();
- job_t *jnext;
- int found=0;
-
- static int locked = 0;
-
- locked++;
-
- /*
- job_read may fire an event handler, we do not want to call
- ourselves recursively (to avoid infinite recursion).
- */
- if( locked>1 )
- return 0;
-
+ job_t *jnext;
+ int found=0;
+
+ static int locked = 0;
+
+ locked++;
+
+ /*
+ job_read may fire an event handler, we do not want to call
+ ourselves recursively (to avoid infinite recursion).
+ */
+ if( locked>1 )
+ return 0;
+
job_iterator_t jobs;
jnext = jobs.next();
- while (jnext)
+ while (jnext)
{
job_t *j = jnext;
jnext = jobs.next();
- process_t *p;
+ process_t *p;
+
+ /*
+ If we are reaping only jobs who do not need status messages
+ sent to the console, do not consider reaping jobs that need
+ status messages
+ */
+ if( (!job_get_flag( j, JOB_SKIP_NOTIFICATION ) ) && (!interactive) && (!job_get_flag( j, JOB_FOREGROUND )))
+ {
+ continue;
+ }
+
+ for( p=j->first_process; p; p=p->next )
+ {
+ int s;
+ if( !p->completed )
+ continue;
+
+ if( !p->pid )
+ continue;
+
+ s = p->status;
+
+ proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, p->pid, ( WIFSIGNALED(s)?-1:WEXITSTATUS( s )) );
+
+ if( WIFSIGNALED(s) )
+ {
+ /*
+ Ignore signal SIGPIPE.We issue it ourselves to the pipe
+ writer when the pipe reader dies.
+ */
+ if( WTERMSIG(s) != SIGPIPE )
+ {
+ int proc_is_job = ((p==j->first_process) && (p->next == 0));
+ if( proc_is_job )
+ job_set_flag( j, JOB_NOTIFIED, 1 );
+ if( !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
+ {
+ if( proc_is_job )
+ fwprintf( stdout,
+ _( L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)" ),
+ program_name,
+ j->job_id,
+ j->command_wcstr(),
+ sig2wcs(WTERMSIG(p->status)),
+ signal_get_desc( WTERMSIG(p->status) ) );
+ else
+ fwprintf( stdout,
+ _( L"%ls: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)" ),
+ program_name,
+ p->pid,
+ p->argv0(),
+ j->job_id,
+ j->command_wcstr(),
+ sig2wcs(WTERMSIG(p->status)),
+ signal_get_desc( WTERMSIG(p->status) ) );
+ tputs(clr_eol,1,&writeb);
+ fwprintf (stdout, L"\n" );
+ found=1;
+ }
+
+ /*
+ Clear status so it is not reported more than once
+ */
+ p->status = 0;
+ }
+ }
+ }
+
+ /*
+ If all processes have completed, tell the user the job has
+ completed and delete it from the active job list.
+ */
+ if( job_is_completed( j ) )
+ {
+ if( !job_get_flag( j, JOB_FOREGROUND) && !job_get_flag( j, JOB_NOTIFIED ) && !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
+ {
+ format_job_info( j, _( L"ended" ) );
+ found=1;
+ }
+ proc_fire_event( L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0 );
+ proc_fire_event( L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0 );
- /*
- If we are reaping only jobs who do not need status messages
- sent to the console, do not consider reaping jobs that need
- status messages
- */
- if( (!job_get_flag( j, JOB_SKIP_NOTIFICATION ) ) && (!interactive) && (!job_get_flag( j, JOB_FOREGROUND )))
- {
- continue;
- }
+ job_free(j);
+ }
+ else if( job_is_stopped( j ) && !job_get_flag( j, JOB_NOTIFIED ) )
+ {
+ /*
+ Notify the user about newly stopped jobs.
+ */
+ if( !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
+ {
+ format_job_info( j, _( L"stopped" ) );
+ found=1;
+ }
+ job_set_flag( j, JOB_NOTIFIED, 1 );
+ }
+ }
- for( p=j->first_process; p; p=p->next )
- {
- int s;
- if( !p->completed )
- continue;
+ if( found )
+ fflush( stdout );
- if( !p->pid )
- continue;
-
- s = p->status;
-
- proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, p->pid, ( WIFSIGNALED(s)?-1:WEXITSTATUS( s )) );
-
- if( WIFSIGNALED(s) )
- {
- /*
- Ignore signal SIGPIPE.We issue it ourselves to the pipe
- writer when the pipe reader dies.
- */
- if( WTERMSIG(s) != SIGPIPE )
- {
- int proc_is_job = ((p==j->first_process) && (p->next == 0));
- if( proc_is_job )
- job_set_flag( j, JOB_NOTIFIED, 1 );
- if( !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
- {
- if( proc_is_job )
- fwprintf( stdout,
- _( L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)" ),
- program_name,
- j->job_id,
- j->command_wcstr(),
- sig2wcs(WTERMSIG(p->status)),
- signal_get_desc( WTERMSIG(p->status) ) );
- else
- fwprintf( stdout,
- _( L"%ls: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)" ),
- program_name,
- p->pid,
- p->argv0(),
- j->job_id,
- j->command_wcstr(),
- sig2wcs(WTERMSIG(p->status)),
- signal_get_desc( WTERMSIG(p->status) ) );
- tputs(clr_eol,1,&writeb);
- fwprintf (stdout, L"\n" );
- found=1;
- }
-
- /*
- Clear status so it is not reported more than once
- */
- p->status = 0;
- }
- }
- }
-
- /*
- If all processes have completed, tell the user the job has
- completed and delete it from the active job list.
- */
- if( job_is_completed( j ) )
- {
- if( !job_get_flag( j, JOB_FOREGROUND) && !job_get_flag( j, JOB_NOTIFIED ) && !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
- {
- format_job_info( j, _( L"ended" ) );
- found=1;
- }
- proc_fire_event( L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0 );
- proc_fire_event( L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0 );
-
- job_free(j);
- }
- else if( job_is_stopped( j ) && !job_get_flag( j, JOB_NOTIFIED ) )
- {
- /*
- Notify the user about newly stopped jobs.
- */
- if( !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
- {
- format_job_info( j, _( L"stopped" ) );
- found=1;
- }
- job_set_flag( j, JOB_NOTIFIED, 1 );
- }
- }
-
- if( found )
- fflush( stdout );
-
- locked = 0;
-
- return found;
+ locked = 0;
+
+ return found;
}
@@ -746,83 +747,83 @@ int job_reap( bool interactive )
*/
unsigned long proc_get_jiffies( process_t *p )
{
- wchar_t fn[FN_SIZE];
+ wchar_t fn[FN_SIZE];
- char state;
- int pid, ppid, pgrp,
- session, tty_nr, tpgid,
- exit_signal, processor;
+ char state;
+ int pid, ppid, pgrp,
+ session, tty_nr, tpgid,
+ exit_signal, processor;
+
+ long int cutime, cstime, priority,
+ nice, placeholder, itrealvalue,
+ rss;
+ unsigned long int flags, minflt, cminflt,
+ majflt, cmajflt, utime,
+ stime, starttime, vsize,
+ rlim, startcode, endcode,
+ startstack, kstkesp, kstkeip,
+ signal, blocked, sigignore,
+ sigcatch, wchan, nswap, cnswap;
+ char comm[1024];
+
+ if( p->pid <= 0 )
+ return 0;
+
+ swprintf( fn, FN_SIZE, L"/proc/%d/stat", p->pid );
+
+ FILE *f = wfopen( fn, "r" );
+ if( !f )
+ return 0;
+
+ int count = fscanf( f,
+ "%d %s %c "
+ "%d %d %d "
+ "%d %d %lu "
+
+ "%lu %lu %lu "
+ "%lu %lu %lu "
+ "%ld %ld %ld "
- long int cutime, cstime, priority,
- nice, placeholder, itrealvalue,
- rss;
- unsigned long int flags, minflt, cminflt,
- majflt, cmajflt, utime,
- stime, starttime, vsize,
- rlim, startcode, endcode,
- startstack, kstkesp, kstkeip,
- signal, blocked, sigignore,
- sigcatch, wchan, nswap, cnswap;
- char comm[1024];
+ "%ld %ld %ld "
+ "%lu %lu %ld "
+ "%lu %lu %lu "
- if( p->pid <= 0 )
- return 0;
+ "%lu %lu %lu "
+ "%lu %lu %lu "
+ "%lu %lu %lu "
- swprintf( fn, FN_SIZE, L"/proc/%d/stat", p->pid );
+ "%lu %d %d ",
+
+ &pid, comm, &state,
+ &ppid, &pgrp, &session,
+ &tty_nr, &tpgid, &flags,
- FILE *f = wfopen( fn, "r" );
- if( !f )
- return 0;
+ &minflt, &cminflt, &majflt,
+ &cmajflt, &utime, &stime,
+ &cutime, &cstime, &priority,
+
+ &nice, &placeholder, &itrealvalue,
+ &starttime, &vsize, &rss,
+ &rlim, &startcode, &endcode,
- int count = fscanf( f,
- "%d %s %c "
- "%d %d %d "
- "%d %d %lu "
+ &startstack, &kstkesp, &kstkeip,
+ &signal, &blocked, &sigignore,
+ &sigcatch, &wchan, &nswap,
- "%lu %lu %lu "
- "%lu %lu %lu "
- "%ld %ld %ld "
+ &cnswap, &exit_signal, &processor
+ );
- "%ld %ld %ld "
- "%lu %lu %ld "
- "%lu %lu %lu "
-
- "%lu %lu %lu "
- "%lu %lu %lu "
- "%lu %lu %lu "
-
- "%lu %d %d ",
-
- &pid, comm, &state,
- &ppid, &pgrp, &session,
- &tty_nr, &tpgid, &flags,
-
- &minflt, &cminflt, &majflt,
- &cmajflt, &utime, &stime,
- &cutime, &cstime, &priority,
-
- &nice, &placeholder, &itrealvalue,
- &starttime, &vsize, &rss,
- &rlim, &startcode, &endcode,
-
- &startstack, &kstkesp, &kstkeip,
- &signal, &blocked, &sigignore,
- &sigcatch, &wchan, &nswap,
-
- &cnswap, &exit_signal, &processor
- );
-
- if( count < 17 )
- {
- return 0;
- }
-
- /*
- Don't need to check exit status of fclose on read-only streams
- */
- fclose( f );
- return utime+stime+cutime+cstime;
+ if( count < 17 )
+ {
+ return 0;
+ }
+ /*
+ Don't need to check exit status of fclose on read-only streams
+ */
+ fclose( f );
+ return utime+stime+cutime+cstime;
+
}
/**
@@ -830,18 +831,18 @@ unsigned long proc_get_jiffies( process_t *p )
*/
void proc_update_jiffies()
{
- job_t* job;
- process_t *p;
- job_iterator_t j;
+ job_t* job;
+ process_t *p;
+ job_iterator_t j;
- for( job = j.next(); job; job = j.next() )
- {
- for( p=job->first_process; p; p=p->next )
- {
- gettimeofday( &p->last_time, 0 );
- p->last_jiffies = proc_get_jiffies( p );
- }
- }
+ for( job = j.next(); job; job = j.next() )
+ {
+ for( p=job->first_process; p; p=p->next )
+ {
+ gettimeofday( &p->last_time, 0 );
+ p->last_jiffies = proc_get_jiffies( p );
+ }
+ }
}
@@ -849,103 +850,103 @@ void proc_update_jiffies()
/**
Check if there are buffers associated with the job, and select on
- them for a while if available.
-
+ them for a while if available.
+
\param j the job to test
\return 1 if buffers were avaialble, zero otherwise
*/
static int select_try( job_t *j )
{
- fd_set fds;
- int maxfd=-1;
-
- FD_ZERO(&fds);
+ fd_set fds;
+ int maxfd=-1;
+ FD_ZERO(&fds);
+
for (size_t idx = 0; idx < j->io.size(); idx++)
- {
+ {
const io_data_t *d = j->io.at(idx);
- if( d->io_mode == IO_BUFFER )
- {
- int fd = d->param1.pipe_fd[0];
-// fwprintf( stderr, L"fd %d on job %ls\n", fd, j->command );
- FD_SET( fd, &fds );
- maxfd = maxi(maxfd, fd);
- debug( 3, L"select_try on %d\n", fd );
- }
- }
+ if( d->io_mode == IO_BUFFER )
+ {
+ int fd = d->param1.pipe_fd[0];
+// fwprintf( stderr, L"fd %d on job %ls\n", fd, j->command );
+ FD_SET( fd, &fds );
+ maxfd = maxi(maxfd, fd);
+ debug( 3, L"select_try on %d\n", fd );
+ }
+ }
+
+ if( maxfd >= 0 )
+ {
+ int retval;
+ struct timeval tv;
+
+ tv.tv_sec=0;
+ tv.tv_usec=10000;
+
+ retval =select( maxfd+1, &fds, 0, 0, &tv );
+ return retval > 0;
+ }
- if( maxfd >= 0 )
- {
- int retval;
- struct timeval tv;
-
- tv.tv_sec=0;
- tv.tv_usec=10000;
-
- retval =select( maxfd+1, &fds, 0, 0, &tv );
- return retval > 0;
- }
-
- return -1;
+ return -1;
}
/**
- Read from descriptors until they are empty.
+ Read from descriptors until they are empty.
\param j the job to test
*/
static void read_try( job_t *j )
{
- io_data_t *buff=NULL;
+ io_data_t *buff=NULL;
- /*
- Find the last buffer, which is the one we want to read from
- */
+ /*
+ Find the last buffer, which is the one we want to read from
+ */
for (size_t idx = 0; idx < j->io.size(); idx++)
- {
+ {
io_data_t *d = j->io.at(idx);
- if( d->io_mode == IO_BUFFER )
- {
- buff=d;
- }
- }
-
- if( buff )
- {
- debug( 3, L"proc::read_try('%ls')\n", j->command_wcstr() );
- while(1)
- {
- char b[BUFFER_SIZE];
- long l;
-
- l=read_blocked( buff->param1.pipe_fd[0],
- b, BUFFER_SIZE );
- if( l==0 )
- {
- break;
- }
- else if( l<0 )
- {
- if( errno != EAGAIN )
- {
- debug( 1,
- _( L"An error occured while reading output from code block" ) );
- wperror( L"read_try" );
- }
- break;
- }
- else
- {
+ if( d->io_mode == IO_BUFFER )
+ {
+ buff=d;
+ }
+ }
+
+ if( buff )
+ {
+ debug( 3, L"proc::read_try('%ls')\n", j->command_wcstr() );
+ while(1)
+ {
+ char b[BUFFER_SIZE];
+ long l;
+
+ l=read_blocked( buff->param1.pipe_fd[0],
+ b, BUFFER_SIZE );
+ if( l==0 )
+ {
+ break;
+ }
+ else if( l<0 )
+ {
+ if( errno != EAGAIN )
+ {
+ debug( 1,
+ _( L"An error occured while reading output from code block" ) );
+ wperror( L"read_try" );
+ }
+ break;
+ }
+ else
+ {
buff->out_buffer_append(b, l);
- }
- }
- }
+ }
+ }
+ }
}
/**
- Give ownership of the terminal to the specified job.
+ Give ownership of the terminal to the specified job.
\param j The job to give the terminal to.
@@ -955,363 +956,363 @@ static void read_try( job_t *j )
*/
static int terminal_give_to_job( job_t *j, int cont )
{
-
- if( tcsetpgrp (0, j->pgid) )
- {
- debug( 1,
- _( L"Could not send job %d ('%ls') to foreground" ),
- j->job_id,
- j->command_wcstr() );
- wperror( L"tcsetpgrp" );
- return 0;
- }
-
- if( cont )
- {
- if( tcsetattr (0, TCSADRAIN, &j->tmodes))
- {
- debug( 1,
- _( L"Could not send job %d ('%ls') to foreground" ),
- j->job_id,
- j->command_wcstr() );
- wperror( L"tcsetattr" );
- return 0;
- }
- }
- return 1;
+
+ if( tcsetpgrp (0, j->pgid) )
+ {
+ debug( 1,
+ _( L"Could not send job %d ('%ls') to foreground" ),
+ j->job_id,
+ j->command_wcstr() );
+ wperror( L"tcsetpgrp" );
+ return 0;
+ }
+
+ if( cont )
+ {
+ if( tcsetattr (0, TCSADRAIN, &j->tmodes))
+ {
+ debug( 1,
+ _( L"Could not send job %d ('%ls') to foreground" ),
+ j->job_id,
+ j->command_wcstr() );
+ wperror( L"tcsetattr" );
+ return 0;
+ }
+ }
+ return 1;
}
/**
Returns contol of the terminal to the shell, and saves the terminal
attribute state to the job, so that we can restore the terminal
- ownership to the job at a later time .
+ ownership to the job at a later time .
*/
static int terminal_return_from_job( job_t *j)
{
-
- if( tcsetpgrp (0, getpgrp()) )
- {
- debug( 1, _( L"Could not return shell to foreground" ) );
- wperror( L"tcsetpgrp" );
- return 0;
- }
-
- /*
- Save jobs terminal modes.
- */
- if( tcgetattr (0, &j->tmodes) )
- {
- debug( 1, _( L"Could not return shell to foreground" ) );
- wperror( L"tcgetattr" );
- return 0;
- }
-
+
+ if( tcsetpgrp (0, getpgrp()) )
+ {
+ debug( 1, _( L"Could not return shell to foreground" ) );
+ wperror( L"tcsetpgrp" );
+ return 0;
+ }
+
+ /*
+ Save jobs terminal modes.
+ */
+ if( tcgetattr (0, &j->tmodes) )
+ {
+ debug( 1, _( L"Could not return shell to foreground" ) );
+ wperror( L"tcgetattr" );
+ return 0;
+ }
+
/* Disabling this per https://github.com/adityagodbole/fish-shell/commit/9d229cd18c3e5c25a8bd37e9ddd3b67ddc2d1b72
On Linux, 'cd . ; ftp' prevents you from typing into the ftp prompt
See https://github.com/fish-shell/fish-shell/issues/121
*/
#if 0
- /*
- Restore the shell's terminal modes.
- */
- if( tcsetattr (0, TCSADRAIN, &shell_modes))
- {
- debug( 1, _( L"Could not return shell to foreground" ) );
- wperror( L"tcsetattr" );
- return 0;
- }
+ /*
+ Restore the shell's terminal modes.
+ */
+ if( tcsetattr (0, TCSADRAIN, &shell_modes))
+ {
+ debug( 1, _( L"Could not return shell to foreground" ) );
+ wperror( L"tcsetattr" );
+ return 0;
+ }
#endif
- return 1;
+ return 1;
}
void job_continue (job_t *j, int cont)
{
- /*
- Put job first in the job list
- */
+ /*
+ Put job first in the job list
+ */
job_promote(j);
- job_set_flag( j, JOB_NOTIFIED, 0 );
+ job_set_flag( j, JOB_NOTIFIED, 0 );
- CHECK_BLOCK();
+ CHECK_BLOCK();
+
+ debug( 4,
+ L"Continue job %d, gid %d (%ls), %ls, %ls",
+ j->job_id,
+ j->pgid,
+ j->command_wcstr(),
+ job_is_completed( j )?L"COMPLETED":L"UNCOMPLETED",
+ is_interactive?L"INTERACTIVE":L"NON-INTERACTIVE" );
+
+ if( !job_is_completed( j ) )
+ {
+ if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
+ {
+ /* Put the job into the foreground. */
+ int ok;
+
+ signal_block();
+
+ ok = terminal_give_to_job( j, cont );
+
+ signal_unblock();
- debug( 4,
- L"Continue job %d, gid %d (%ls), %ls, %ls",
- j->job_id,
- j->pgid,
- j->command_wcstr(),
- job_is_completed( j )?L"COMPLETED":L"UNCOMPLETED",
- is_interactive?L"INTERACTIVE":L"NON-INTERACTIVE" );
+ if( !ok )
+ return;
+
+ }
+
+ /*
+ Send the job a continue signal, if necessary.
+ */
+ if( cont )
+ {
+ process_t *p;
- if( !job_is_completed( j ) )
- {
- if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
- {
- /* Put the job into the foreground. */
- int ok;
+ for( p=j->first_process; p; p=p->next )
+ p->stopped=0;
- signal_block();
+ if( job_get_flag( j, JOB_CONTROL ) )
+ {
+ if( killpg( j->pgid, SIGCONT ) )
+ {
+ wperror( L"killpg (SIGCONT)" );
+ return;
+ }
+ }
+ else
+ {
+ for( p=j->first_process; p; p=p->next )
+ {
+ if (kill ( p->pid, SIGCONT) < 0)
+ {
+ wperror (L"kill (SIGCONT)");
+ return;
+ }
+ }
+ }
+ }
+
+ if( job_get_flag( j, JOB_FOREGROUND ) )
+ {
+ int quit = 0;
+
+ /*
+ Wait for job to report. Looks a bit ugly because it has to
+ handle the possibility that a signal is dispatched while
+ running job_is_stopped().
+ */
+ while( !quit )
+ {
+ do
+ {
+ got_signal = 0;
+ quit = job_is_stopped( j ) || job_is_completed( j );
+ }
+ while (got_signal && !quit);
+
+ if( !quit )
+ {
+
+// debug( 1, L"select_try()" );
+ switch( select_try(j) )
+ {
+ case 1:
+ {
+ read_try( j );
+ break;
+ }
+
+ case -1:
+ {
+ /*
+ If there is no funky IO magic, we can use
+ waitpid instead of handling child deaths
+ through signals. This gives a rather large
+ speed boost (A factor 3 startup time
+ improvement on my 300 MHz machine) on
+ short-lived jobs.
+ */
+ int status;
+ pid_t pid = waitpid(-1, &status, WUNTRACED );
+ if( pid > 0 )
+ {
+ handle_child_status( pid, status );
+ }
+ else
+ {
+ /*
+ This probably means we got a
+ signal. A signal might mean that the
+ terminal emulator sent us a hup
+ signal to tell is to close. If so,
+ we should exit.
+ */
+ if( reader_exit_forced() )
+ {
+ quit = 1;
+ }
+
+ }
+ break;
+ }
+
+ }
+ }
+ }
+ }
+ }
+
+ if( job_get_flag( j, JOB_FOREGROUND ) )
+ {
+
+ if( job_is_completed( j ))
+ {
+
+ // It's possible that the job will produce output and exit before we've even read from it.
+ // We'll eventually read the output, but it may be after we've executed subsequent calls
+ // This is why my prompt colors kept getting screwed up - the builtin echo calls
+ // were sometimes having their output combined with the set_color calls in the wrong order!
+ read_try(j);
- ok = terminal_give_to_job( j, cont );
+
+ process_t *p = j->first_process;
+ while( p->next )
+ p = p->next;
- signal_unblock();
-
- if( !ok )
- return;
-
- }
-
- /*
- Send the job a continue signal, if necessary.
- */
- if( cont )
- {
- process_t *p;
-
- for( p=j->first_process; p; p=p->next )
- p->stopped=0;
-
- if( job_get_flag( j, JOB_CONTROL ) )
- {
- if( killpg( j->pgid, SIGCONT ) )
- {
- wperror( L"killpg (SIGCONT)" );
- return;
- }
- }
- else
- {
- for( p=j->first_process; p; p=p->next )
- {
- if (kill ( p->pid, SIGCONT) < 0)
- {
- wperror (L"kill (SIGCONT)");
- return;
- }
- }
- }
- }
-
- if( job_get_flag( j, JOB_FOREGROUND ) )
- {
- int quit = 0;
-
- /*
- Wait for job to report. Looks a bit ugly because it has to
- handle the possibility that a signal is dispatched while
- running job_is_stopped().
- */
- while( !quit )
- {
- do
- {
- got_signal = 0;
- quit = job_is_stopped( j ) || job_is_completed( j );
- }
- while (got_signal && !quit);
-
- if( !quit )
- {
-
-// debug( 1, L"select_try()" );
- switch( select_try(j) )
- {
- case 1:
- {
- read_try( j );
- break;
- }
-
- case -1:
- {
- /*
- If there is no funky IO magic, we can use
- waitpid instead of handling child deaths
- through signals. This gives a rather large
- speed boost (A factor 3 startup time
- improvement on my 300 MHz machine) on
- short-lived jobs.
- */
- int status;
- pid_t pid = waitpid(-1, &status, WUNTRACED );
- if( pid > 0 )
- {
- handle_child_status( pid, status );
- }
- else
- {
- /*
- This probably means we got a
- signal. A signal might mean that the
- terminal emulator sent us a hup
- signal to tell is to close. If so,
- we should exit.
- */
- if( reader_exit_forced() )
- {
- quit = 1;
- }
-
- }
- break;
- }
-
- }
- }
- }
- }
- }
-
- if( job_get_flag( j, JOB_FOREGROUND ) )
- {
-
- if( job_is_completed( j ))
- {
-
- // It's possible that the job will produce output and exit before we've even read from it.
- // We'll eventually read the output, but it may be after we've executed subsequent calls
- // This is why my prompt colors kept getting screwed up - the builtin echo calls
- // were sometimes having their output combined with the set_color calls in the wrong order!
- read_try(j);
-
-
- process_t *p = j->first_process;
- while( p->next )
- p = p->next;
-
- if( WIFEXITED( p->status ) || WIFSIGNALED(p->status))
- {
- /*
- Mark process status only if we are in the foreground
- and the last process in a pipe, and it is not a short circuted builtin
- */
- if( p->pid )
- {
- int status = proc_format_status(p->status);
- //wprintf(L"setting status %d for %ls\n", job_get_flag( j, JOB_NEGATE )?!status:status, j->command);
- proc_set_last_status( job_get_flag( j, JOB_NEGATE )?!status:status);
- }
- }
- }
- /*
- Put the shell back in the foreground.
- */
- if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
- {
- int ok;
-
- signal_block();
-
- ok = terminal_return_from_job( j );
-
- signal_unblock();
-
- if( !ok )
- return;
-
- }
- }
+ if( WIFEXITED( p->status ) || WIFSIGNALED(p->status))
+ {
+ /*
+ Mark process status only if we are in the foreground
+ and the last process in a pipe, and it is not a short circuted builtin
+ */
+ if( p->pid )
+ {
+ int status = proc_format_status(p->status);
+ //wprintf(L"setting status %d for %ls\n", job_get_flag( j, JOB_NEGATE )?!status:status, j->command);
+ proc_set_last_status( job_get_flag( j, JOB_NEGATE )?!status:status);
+ }
+ }
+ }
+ /*
+ Put the shell back in the foreground.
+ */
+ if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
+ {
+ int ok;
+
+ signal_block();
+ ok = terminal_return_from_job( j );
+
+ signal_unblock();
+
+ if( !ok )
+ return;
+
+ }
+ }
+
}
-int proc_format_status(int status)
+int proc_format_status(int status)
{
- if( WIFSIGNALED( status ) )
- {
- return 128+WTERMSIG(status);
- }
- else if( WIFEXITED( status ) )
- {
- return WEXITSTATUS(status);
- }
- return status;
-
+ if( WIFSIGNALED( status ) )
+ {
+ return 128+WTERMSIG(status);
+ }
+ else if( WIFEXITED( status ) )
+ {
+ return WEXITSTATUS(status);
+ }
+ return status;
+
}
void proc_sanity_check()
{
- job_t *j;
- job_t *fg_job=0;
-
+ job_t *j;
+ job_t *fg_job=0;
+
job_iterator_t jobs;
while ((j = jobs.next()))
- {
- process_t *p;
+ {
+ process_t *p;
- if( !job_get_flag( j, JOB_CONSTRUCTED ) )
- continue;
+ if( !job_get_flag( j, JOB_CONSTRUCTED ) )
+ continue;
+
+
+ validate_pointer( j->first_process,
+ _( L"Process list pointer" ),
+ 0 );
-
- validate_pointer( j->first_process,
- _( L"Process list pointer" ),
- 0 );
-
- /*
- More than one foreground job?
- */
- if( job_get_flag( j, JOB_FOREGROUND ) && !(job_is_stopped(j) || job_is_completed(j) ) )
- {
- if( fg_job != 0 )
- {
- debug( 0,
- _( L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"),
- fg_job->command_wcstr(),
- j->command_wcstr() );
- sanity_lose();
- }
- fg_job = j;
- }
-
- p = j->first_process;
- while( p )
- {
- validate_pointer( p->get_argv(), _( L"Process argument list" ), 0 );
- validate_pointer( p->argv0(), _( L"Process name" ), 0 );
- validate_pointer( p->next, _( L"Process list pointer" ), 1 );
-
- if ( (p->stopped & (~0x00000001)) != 0 )
- {
- debug( 0,
- _( L"Job '%ls', process '%ls' has inconsistent state \'stopped\'=%d" ),
- j->command_wcstr(),
- p->argv0(),
- p->stopped );
- sanity_lose();
- }
-
- if ( (p->completed & (~0x00000001)) != 0 )
- {
- debug( 0,
- _( L"Job '%ls', process '%ls' has inconsistent state \'completed\'=%d" ),
- j->command_wcstr(),
- p->argv0(),
- p->completed );
- sanity_lose();
- }
-
- p=p->next;
- }
-
- }
+ /*
+ More than one foreground job?
+ */
+ if( job_get_flag( j, JOB_FOREGROUND ) && !(job_is_stopped(j) || job_is_completed(j) ) )
+ {
+ if( fg_job != 0 )
+ {
+ debug( 0,
+ _( L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"),
+ fg_job->command_wcstr(),
+ j->command_wcstr() );
+ sanity_lose();
+ }
+ fg_job = j;
+ }
+
+ p = j->first_process;
+ while( p )
+ {
+ validate_pointer( p->get_argv(), _( L"Process argument list" ), 0 );
+ validate_pointer( p->argv0(), _( L"Process name" ), 0 );
+ validate_pointer( p->next, _( L"Process list pointer" ), 1 );
+
+ if ( (p->stopped & (~0x00000001)) != 0 )
+ {
+ debug( 0,
+ _( L"Job '%ls', process '%ls' has inconsistent state \'stopped\'=%d" ),
+ j->command_wcstr(),
+ p->argv0(),
+ p->stopped );
+ sanity_lose();
+ }
+
+ if ( (p->completed & (~0x00000001)) != 0 )
+ {
+ debug( 0,
+ _( L"Job '%ls', process '%ls' has inconsistent state \'completed\'=%d" ),
+ j->command_wcstr(),
+ p->argv0(),
+ p->completed );
+ sanity_lose();
+ }
+
+ p=p->next;
+ }
+
+ }
}
void proc_push_interactive( int value )
{
ASSERT_IS_MAIN_THREAD();
- int old = is_interactive;
+ int old = is_interactive;
interactive_stack.push_back(is_interactive);
- is_interactive = value;
- if( old != value )
- signal_set_handlers();
+ is_interactive = value;
+ if( old != value )
+ signal_set_handlers();
}
void proc_pop_interactive()
{
ASSERT_IS_MAIN_THREAD();
- int old = is_interactive;
- is_interactive= interactive_stack.back();
+ int old = is_interactive;
+ is_interactive= interactive_stack.back();
interactive_stack.pop_back();
- if( is_interactive != old )
- signal_set_handlers();
+ if( is_interactive != old )
+ signal_set_handlers();
}
diff --git a/reader.cpp b/reader.cpp
index 3c19557b8..921dd9870 100644
--- a/reader.cpp
+++ b/reader.cpp
@@ -194,131 +194,135 @@ typedef int color_t;
class reader_data_t
{
public:
-
- /** String containing the whole current commandline */
- wcstring command_line;
-
+
+ /** String containing the whole current commandline */
+ wcstring command_line;
+
/** String containing the autosuggestion */
wcstring autosuggestion;
- /** When backspacing, we suppress autosuggestions */
+ /** Whether autosuggesting is allowed at all */
+ bool allow_autosuggestion;
+
+ /** When backspacing, we temporarily suppress autosuggestions */
bool suppress_autosuggestion;
- /** The representation of the current screen contents */
- screen_t screen;
-
+ /** The representation of the current screen contents */
+ screen_t screen;
+
/** The history */
history_t *history;
- /**
- String containing the current search item
- */
- wcstring search_buff;
+ /**
+ String containing the current search item
+ */
+ wcstring search_buff;
/* History search */
history_search_t history_search;
- /**
- Saved position used by token history search
- */
- int token_history_pos;
+ /**
+ Saved position used by token history search
+ */
+ int token_history_pos;
- /**
- Saved search string for token history search. Not handled by command_line_changed.
- */
- wcstring token_history_buff;
+ /**
+ Saved search string for token history search. Not handled by command_line_changed.
+ */
+ wcstring token_history_buff;
- /**
- List for storing previous search results. Used to avoid duplicates.
- */
- wcstring_list_t search_prev;
-
- /** The current position in search_prev */
- size_t search_pos;
+ /**
+ List for storing previous search results. Used to avoid duplicates.
+ */
+ wcstring_list_t search_prev;
+ /** The current position in search_prev */
+ size_t search_pos;
+
/** Length of the command */
size_t command_length() const { return command_line.size(); }
-
+
/** Do what we need to do whenever our command line changes */
void command_line_changed(void);
- /** The current position of the cursor in buff. */
- size_t buff_pos;
+ /** The current position of the cursor in buff. */
+ size_t buff_pos;
- /** Name of the current application */
- wcstring app_name;
+ /** Name of the current application */
+ wcstring app_name;
- /** The prompt commands */
- wcstring left_prompt;
+ /** The prompt commands */
+ wcstring left_prompt;
wcstring right_prompt;
- /** The output of the last evaluation of the prompt command */
- wcstring left_prompt_buff;
-
- /** The output of the last evaluation of the right prompt command */
- wcstring right_prompt_buff;
-
- /**
- Color is the syntax highlighting for buff. The format is that
- color[i] is the classification (according to the enum in
- highlight.h) of buff[i].
- */
+ /** The output of the last evaluation of the prompt command */
+ wcstring left_prompt_buff;
+
+ /** The output of the last evaluation of the right prompt command */
+ wcstring right_prompt_buff;
+
+ /**
+ Color is the syntax highlighting for buff. The format is that
+ color[i] is the classification (according to the enum in
+ highlight.h) of buff[i].
+ */
std::vector colors;
- /** An array defining the block level at each character. */
- std::vector indents;
+ /** An array defining the block level at each character. */
+ std::vector indents;
- /**
- Function for tab completion
- */
+ /**
+ Function for tab completion
+ */
complete_function_t complete_func;
- /**
- Function for syntax highlighting
- */
- highlight_function_t highlight_function;
+ /**
+ Function for syntax highlighting
+ */
+ highlight_function_t highlight_function;
- /**
- Function for testing if the string can be returned
- */
- int (*test_func)( const wchar_t * );
+ /**
+ Function for testing if the string can be returned
+ */
+ int (*test_func)( const wchar_t * );
- /**
- When this is true, the reader will exit
- */
- bool end_loop;
+ /**
+ When this is true, the reader will exit
+ */
+ bool end_loop;
- /**
- If this is true, exit reader even if there are running
- jobs. This happens if we press e.g. ^D twice.
- */
- bool prev_end_loop;
+ /**
+ If this is true, exit reader even if there are running
+ jobs. This happens if we press e.g. ^D twice.
+ */
+ bool prev_end_loop;
- /** The current contents of the top item in the kill ring. */
- wcstring kill_item;
+ /** The current contents of the top item in the kill ring. */
+ wcstring kill_item;
- /**
- Pointer to previous reader_data
- */
- reader_data_t *next;
+ /**
+ Pointer to previous reader_data
+ */
+ reader_data_t *next;
- /**
- This variable keeps state on if we are in search mode, and
- if yes, what mode
- */
- int search_mode;
-
- /**
- Keep track of whether any internal code has done something
- which is known to require a repaint.
- */
- bool repaint_needed;
+ /**
+ This variable keeps state on if we are in search mode, and
+ if yes, what mode
+ */
+ int search_mode;
+ /**
+ Keep track of whether any internal code has done something
+ which is known to require a repaint.
+ */
+ bool repaint_needed;
+
/** Whether the a screen reset is needed after a repaint. */
bool screen_reset_needed;
-
+
/** Constructor */
reader_data_t() :
+ allow_autosuggestion(0),
suppress_autosuggestion(0),
history(0),
token_history_pos(0),
@@ -392,22 +396,22 @@ static int exit_forced;
*/
static void term_donate()
{
- set_color(rgb_color_t::normal(), rgb_color_t::normal());
+ set_color(rgb_color_t::normal(), rgb_color_t::normal());
- while( 1 )
- {
- if( tcsetattr(0,TCSANOW,&saved_modes) )
- {
- if( errno != EINTR )
- {
- debug( 1, _( L"Could not set terminal mode for new job" ) );
- wperror( L"tcsetattr" );
- break;
- }
- }
- else
- break;
- }
+ while( 1 )
+ {
+ if( tcsetattr(0,TCSANOW,&saved_modes) )
+ {
+ if( errno != EINTR )
+ {
+ debug( 1, _( L"Could not set terminal mode for new job" ) );
+ wperror( L"tcsetattr" );
+ break;
+ }
+ }
+ else
+ break;
+ }
}
@@ -418,28 +422,28 @@ static void term_donate()
static void term_steal()
{
- while( 1 )
- {
- if( tcsetattr(0,TCSANOW,&shell_modes) )
- {
- if( errno != EINTR )
- {
- debug( 1, _( L"Could not set terminal mode for shell" ) );
- wperror( L"tcsetattr" );
- break;
- }
- }
- else
- break;
- }
+ while( 1 )
+ {
+ if( tcsetattr(0,TCSANOW,&shell_modes) )
+ {
+ if( errno != EINTR )
+ {
+ debug( 1, _( L"Could not set terminal mode for shell" ) );
+ wperror( L"tcsetattr" );
+ break;
+ }
+ }
+ else
+ break;
+ }
- common_handle_winch(0 );
+ common_handle_winch(0 );
}
int reader_exit_forced()
{
- return exit_forced;
+ return exit_forced;
}
/**
@@ -451,16 +455,16 @@ int reader_exit_forced()
static void reader_repaint()
{
//Update the indentation
- parser_t::principal_parser().test( data->command_line.c_str(), &data->indents[0], 0, 0 );
-
+ parser_t::principal_parser().test( data->command_line.c_str(), &data->indents[0], 0, 0 );
+
wcstring full_line = (data->autosuggestion.empty() ? data->command_line : data->autosuggestion);
size_t len = full_line.size();
if (len < 1)
len = 1;
-
+
std::vector colors = data->colors;
colors.resize(len, HIGHLIGHT_AUTOSUGGESTION);
-
+
std::vector indents = data->indents;
indents.resize(len);
@@ -473,7 +477,7 @@ static void reader_repaint()
&indents[0],
data->buff_pos);
- data->repaint_needed = false;
+ data->repaint_needed = false;
}
/**
@@ -482,53 +486,53 @@ static void reader_repaint()
static void reader_kill( size_t begin_idx, size_t length, int mode, int newv )
{
const wchar_t *begin = data->command_line.c_str() + begin_idx;
- if( newv )
- {
+ if( newv )
+ {
data->kill_item = wcstring(begin, length);
- kill_add(data->kill_item);
- }
- else
- {
+ kill_add(data->kill_item);
+ }
+ else
+ {
wcstring old = data->kill_item;
- if( mode == KILL_APPEND )
- {
+ if( mode == KILL_APPEND )
+ {
data->kill_item.append(begin, length);
- }
- else
- {
+ }
+ else
+ {
data->kill_item = wcstring(begin, length);
data->kill_item.append(old);
- }
+ }
+
+ kill_replace( old, data->kill_item );
+ }
- kill_replace( old, data->kill_item );
- }
-
- if( data->buff_pos > begin_idx ) {
+ if( data->buff_pos > begin_idx ) {
/* Move the buff position back by the number of characters we deleted, but don't go past buff_pos */
size_t backtrack = mini(data->buff_pos - begin_idx, length);
data->buff_pos -= backtrack;
- }
-
+ }
+
data->command_line.erase(begin_idx, length);
data->command_line_changed();
-
- reader_super_highlight_me_plenty( data->buff_pos );
- reader_repaint();
-
+
+ reader_super_highlight_me_plenty( data->buff_pos );
+ reader_repaint();
+
}
/* This is called from a signal handler! */
void reader_handle_int( int sig )
{
- if( !is_interactive_read )
- {
+ if( !is_interactive_read )
+ {
parser_t::skip_all_blocks();
- }
-
- interrupted = 1;
-
+ }
+
+ interrupted = 1;
+
}
const wchar_t *reader_current_filename()
@@ -548,7 +552,7 @@ void reader_push_current_filename( const wchar_t *fn )
void reader_pop_current_filename()
{
ASSERT_IS_MAIN_THREAD();
- current_filename.pop();
+ current_filename.pop();
}
@@ -556,13 +560,13 @@ void reader_pop_current_filename()
void reader_data_t::command_line_changed() {
ASSERT_IS_MAIN_THREAD();
size_t len = command_length();
-
+
/* When we grow colors, propagate the last color (if any), under the assumption that usually it will be correct. If it is, it avoids a repaint. */
color_t last_color = colors.empty() ? color_t() : colors.back();
colors.resize(len, last_color);
-
+
indents.resize(len);
-
+
/* Update the gen count */
s_generation_count++;
}
@@ -571,84 +575,84 @@ void reader_data_t::command_line_changed() {
/** Remove any duplicate completions in the list. This relies on the list first beeing sorted. */
static void remove_duplicates(std::vector &l)
{
- l.erase(std::unique( l.begin(), l.end()), l.end());
+ l.erase(std::unique( l.begin(), l.end()), l.end());
}
int reader_interrupted()
{
- int res=interrupted;
- if( res )
- interrupted=0;
- return res;
+ int res=interrupted;
+ if( res )
+ interrupted=0;
+ return res;
}
void reader_write_title()
{
- const wchar_t *title;
- const env_var_t term_str = env_get_string( L"TERM" );
+ const wchar_t *title;
+ const env_var_t term_str = env_get_string( L"TERM" );
- /*
- This is a pretty lame heuristic for detecting terminals that do
- not support setting the title. If we recognise the terminal name
- as that of a virtual terminal, we assume it supports setting the
- title. If we recognise it as that of a console, we assume it
- does not support setting the title. Otherwise we check the
- ttyname and see if we belive it is a virtual terminal.
+ /*
+ This is a pretty lame heuristic for detecting terminals that do
+ not support setting the title. If we recognise the terminal name
+ as that of a virtual terminal, we assume it supports setting the
+ title. If we recognise it as that of a console, we assume it
+ does not support setting the title. Otherwise we check the
+ ttyname and see if we belive it is a virtual terminal.
- One situation in which this breaks down is with screen, since
- screen supports setting the terminal title if the underlying
- terminal does so, but will print garbage on terminals that
- don't. Since we can't see the underlying terminal below screen
- there is no way to fix this.
- */
- if ( term_str.missing() )
- return;
+ One situation in which this breaks down is with screen, since
+ screen supports setting the terminal title if the underlying
+ terminal does so, but will print garbage on terminals that
+ don't. Since we can't see the underlying terminal below screen
+ there is no way to fix this.
+ */
+ if ( term_str.missing() )
+ return;
- const wchar_t *term = term_str.c_str();
+ const wchar_t *term = term_str.c_str();
bool recognized = false;
recognized = recognized || contains( term, L"xterm", L"screen", L"nxterm", L"rxvt" );
recognized = recognized || ! wcsncmp(term, L"xterm-", wcslen(L"xterm-"));
recognized = recognized || ! wcsncmp(term, L"screen-", wcslen(L"screen-"));
- if( ! recognized )
- {
- char *n = ttyname( STDIN_FILENO );
+ if( ! recognized )
+ {
+ char *n = ttyname( STDIN_FILENO );
- if( contains( term, L"linux" ) )
- {
- return;
- }
+ if( contains( term, L"linux" ) )
+ {
+ return;
+ }
- if( strstr( n, "tty" ) || strstr( n, "/vc/") )
- return;
+ if( strstr( n, "tty" ) || strstr( n, "/vc/") )
+ return;
+
+
+ }
+ title = function_exists( L"fish_title" )?L"fish_title":DEFAULT_TITLE;
- }
-
- title = function_exists( L"fish_title" )?L"fish_title":DEFAULT_TITLE;
-
- if( wcslen( title ) ==0 )
- return;
+ if( wcslen( title ) ==0 )
+ return;
wcstring_list_t lst;
- proc_push_interactive(0);
- if( exec_subshell( title, lst ) != -1 )
- {
- size_t i;
- if( lst.size() > 0 )
- {
- writestr( L"\x1b]0;" );
- for( i=0; i 0 )
+ {
+ writestr( L"\x1b]0;" );
+ for( i=0; ileft_prompt_buff.clear();
data->right_prompt_buff.clear();
-
+
/* If we have any prompts, they must be run non-interactively */
if (data->left_prompt.size() || data->right_prompt.size())
{
proc_push_interactive( 0 );
-
+
if (data->left_prompt.size())
{
wcstring_list_t prompt_list;
@@ -677,7 +681,7 @@ static void exec_prompt()
}
}
}
-
+
if (data->right_prompt.size())
{
wcstring_list_t prompt_list;
@@ -690,34 +694,34 @@ static void exec_prompt()
}
}
}
-
+
proc_pop_interactive();
}
-
+
/* Write the screen title */
- reader_write_title();
+ reader_write_title();
}
void reader_init()
{
- tcgetattr(0,&shell_modes); /* get the current terminal modes */
- memcpy( &saved_modes,
- &shell_modes,
- sizeof(saved_modes)); /* save a copy so we can reset the terminal later */
-
- shell_modes.c_lflag &= ~ICANON; /* turn off canonical mode */
- shell_modes.c_lflag &= ~ECHO; /* turn off echo mode */
+ tcgetattr(0,&shell_modes); /* get the current terminal modes */
+ memcpy( &saved_modes,
+ &shell_modes,
+ sizeof(saved_modes)); /* save a copy so we can reset the terminal later */
+
+ shell_modes.c_lflag &= ~ICANON; /* turn off canonical mode */
+ shell_modes.c_lflag &= ~ECHO; /* turn off echo mode */
shell_modes.c_cc[VMIN]=1;
shell_modes.c_cc[VTIME]=0;
-
+
// PCA disable VDSUSP (typically control-Y), which is a funny job control
// function available only on OS X and BSD systems
// This lets us use control-Y for yank instead
#ifdef VDSUSP
- shell_modes.c_cc[VDSUSP] = _POSIX_VDISABLE;
+ shell_modes.c_cc[VDSUSP] = _POSIX_VDISABLE;
#endif
-
+
/* Repaint if necessary before each byte is read. This lets us react immediately to universal variable color changes. */
input_common_set_poll_callback(reader_repaint_if_needed);
}
@@ -725,25 +729,25 @@ void reader_init()
void reader_destroy()
{
- tcsetattr(0, TCSANOW, &saved_modes);
+ tcsetattr(0, TCSANOW, &saved_modes);
}
void reader_exit( int do_exit, int forced )
{
- if( data )
- data->end_loop=do_exit;
- end_loop=do_exit;
- if( forced )
- exit_forced = 1;
-
+ if( data )
+ data->end_loop=do_exit;
+ end_loop=do_exit;
+ if( forced )
+ exit_forced = 1;
+
}
void reader_repaint_needed()
{
- if (data) {
- data->repaint_needed = true;
- }
+ if (data) {
+ data->repaint_needed = true;
+ }
}
void reader_repaint_if_needed() {
@@ -759,10 +763,10 @@ void reader_repaint_if_needed() {
}
void reader_react_to_color_change() {
- if (data) {
+ if (data) {
data->repaint_needed = true;
data->screen_reset_needed = true;
- }
+ }
}
@@ -773,22 +777,22 @@ void reader_react_to_color_change() {
static void remove_backward()
{
- if( data->buff_pos <= 0 )
- return;
-
+ if( data->buff_pos <= 0 )
+ return;
+
/* Fake composed character sequences by continuning to delete until we delete a character of width at least 1. */
int width;
do {
data->buff_pos -= 1;
width = fish_wcwidth(data->command_line.at(data->buff_pos));
- data->command_line.erase(data->buff_pos, 1);
+ data->command_line.erase(data->buff_pos, 1);
} while (width == 0 && data->buff_pos > 0);
data->command_line_changed();
data->suppress_autosuggestion = true;
- reader_super_highlight_me_plenty( data->buff_pos );
+ reader_super_highlight_me_plenty( data->buff_pos );
- reader_repaint();
+ reader_repaint();
}
@@ -802,18 +806,18 @@ static int insert_string(const wcstring &str)
size_t len = str.size();
if (len == 0)
return 0;
-
+
data->command_line.insert(data->buff_pos, str);
data->buff_pos += len;
data->command_line_changed();
data->suppress_autosuggestion = false;
-
- /* Syntax highlight. Note we must have that buff_pos > 0 because we just added something nonzero to its length */
+
+ /* Syntax highlight. Note we must have that buff_pos > 0 because we just added something nonzero to its length */
assert(data->buff_pos > 0);
- reader_super_highlight_me_plenty( data->buff_pos-1 );
-
- reader_repaint();
- return 1;
+ reader_super_highlight_me_plenty( data->buff_pos-1 );
+
+ reader_repaint();
+ return 1;
}
@@ -823,7 +827,7 @@ static int insert_string(const wcstring &str)
*/
static int insert_char( wchar_t c )
{
- return insert_string(wcstring(&c, 1));
+ return insert_string(wcstring(&c, 1));
}
@@ -832,10 +836,10 @@ static int insert_char( wchar_t c )
*/
static size_t comp_len( const wchar_t *a, const wchar_t *b )
{
- size_t i;
- for( i=0; a[i] != L'\0' && b[i] != L'\0' && a[i]==b[i]; i++ )
- ;
- return i;
+ size_t i;
+ for( i=0; a[i] != L'\0' && b[i] != L'\0' && a[i]==b[i]; i++ )
+ ;
+ return i;
}
/**
@@ -843,10 +847,10 @@ static size_t comp_len( const wchar_t *a, const wchar_t *b )
*/
static size_t comp_ilen( const wchar_t *a, const wchar_t *b )
{
- size_t i;
- for( i=0; a[i] != L'\0' && b[i] != L'\0' && towlower(a[i])==towlower(b[i]); i++ )
- ;
- return i;
+ size_t i;
+ for( i=0; a[i] != L'\0' && b[i] != L'\0' && towlower(a[i])==towlower(b[i]); i++ )
+ ;
+ return i;
}
@@ -863,71 +867,71 @@ static size_t comp_ilen( const wchar_t *a, const wchar_t *b )
static wcstring completion_apply_to_command_line(const wcstring &val_str, int flags, const wcstring &command_line, size_t *inout_cursor_pos)
{
const wchar_t *val = val_str.c_str();
- bool add_space = !(flags & COMPLETE_NO_SPACE);
- bool do_replace = !!(flags & COMPLETE_NO_CASE);
- bool do_escape = !(flags & COMPLETE_DONT_ESCAPE);
+ bool add_space = !(flags & COMPLETE_NO_SPACE);
+ bool do_replace = !!(flags & COMPLETE_NO_CASE);
+ bool do_escape = !(flags & COMPLETE_DONT_ESCAPE);
const size_t cursor_pos = *inout_cursor_pos;
+
+ // debug( 0, L"Insert completion %ls with flags %d", val, flags);
- // debug( 0, L"Insert completion %ls with flags %d", val, flags);
-
- if( do_replace )
- {
-
- size_t move_cursor;
- const wchar_t *begin, *end;
- wchar_t *escaped;
-
+ if( do_replace )
+ {
+
+ size_t move_cursor;
+ const wchar_t *begin, *end;
+ wchar_t *escaped;
+
const wchar_t *buff = command_line.c_str();
- parse_util_token_extent( buff, cursor_pos, &begin, 0, 0, 0 );
- end = buff + cursor_pos;
+ parse_util_token_extent( buff, cursor_pos, &begin, 0, 0, 0 );
+ end = buff + cursor_pos;
- wcstring sb(buff, begin - buff);
-
- if( do_escape )
- {
- escaped = escape( val, ESCAPE_ALL | ESCAPE_NO_QUOTED );
- sb.append( escaped );
- move_cursor = wcslen(escaped);
- free( escaped );
- }
- else
- {
- sb.append( val );
- move_cursor = wcslen(val);
- }
-
-
- if( add_space )
- {
- sb.append( L" " );
- move_cursor += 1;
- }
- sb.append( end );
+ wcstring sb(buff, begin - buff);
+
+ if( do_escape )
+ {
+ escaped = escape( val, ESCAPE_ALL | ESCAPE_NO_QUOTED );
+ sb.append( escaped );
+ move_cursor = wcslen(escaped);
+ free( escaped );
+ }
+ else
+ {
+ sb.append( val );
+ move_cursor = wcslen(val);
+ }
+
+ if( add_space )
+ {
+ sb.append( L" " );
+ move_cursor += 1;
+ }
+ sb.append( end );
+
size_t new_cursor_pos = (begin - buff) + move_cursor;
*inout_cursor_pos = new_cursor_pos;
return sb;
- }
- else
- {
+ }
+ else
+ {
wchar_t quote = L'\0';
wcstring replaced;
- if( do_escape )
- {
+ if( do_escape )
+ {
parse_util_get_parameter_info(command_line, cursor_pos, "e, NULL, NULL);
replaced = parse_util_escape_string_with_quote(val_str, quote);
- }
- else
- {
- replaced = val;
- }
-
+ }
+ else
+ {
+ replaced = val;
+ }
+
wcstring result = command_line;
result.insert(cursor_pos, replaced);
size_t new_cursor_pos = cursor_pos + replaced.size();
if (add_space)
{
- if (quote && (command_line.c_str()[cursor_pos] != quote))
+ if (quote && (command_line.c_str()[cursor_pos] != quote))
{
/* This is a quoted parameter, first print a quote */
result.insert(new_cursor_pos++, wcstring("e, 1));
@@ -936,7 +940,7 @@ static wcstring completion_apply_to_command_line(const wcstring &val_str, int fl
}
*inout_cursor_pos = new_cursor_pos;
return result;
- }
+ }
}
/**
@@ -953,7 +957,7 @@ static void completion_insert( const wchar_t *val, int flags )
size_t cursor = data->buff_pos;
wcstring new_command_line = completion_apply_to_command_line(val, flags, data->command_line, &cursor);
reader_set_buffer(new_command_line, cursor);
-
+
/* Since we just inserted a completion, don't immediately do a new autosuggestion */
data->suppress_autosuggestion = true;
}
@@ -963,7 +967,7 @@ static void completion_insert( const wchar_t *val, int flags )
fish_pager outputs any text, it is inserted into the input
backbuffer.
- \param prefix the string to display before every completion.
+ \param prefix the string to display before every completion.
\param is_quoted should be set if the argument is quoted. This will change the display style.
\param comp the list of completions to display
*/
@@ -971,74 +975,74 @@ static void completion_insert( const wchar_t *val, int flags )
static void run_pager( const wcstring &prefix, int is_quoted, const std::vector &comp )
{
wcstring msg;
- wcstring prefix_esc;
- char *foo;
+ wcstring prefix_esc;
+ char *foo;
- wchar_t *escaped_separator;
- int has_case_sensitive=0;
-
- if (prefix.empty())
- {
- prefix_esc = L"\"\"";
- }
- else
- {
- prefix_esc = escape_string(prefix, 1);
- }
+ wchar_t *escaped_separator;
+ int has_case_sensitive=0;
+ if (prefix.empty())
+ {
+ prefix_esc = L"\"\"";
+ }
+ else
+ {
+ prefix_esc = escape_string(prefix, 1);
+ }
+
wcstring cmd = format_string(L"fish_pager -c 3 -r 4 %ls -p %ls",
// L"valgrind --track-fds=yes --log-file=pager.txt --leak-check=full ./fish_pager %d %ls",
is_quoted?L"-q":L"",
prefix_esc.c_str() );
-
+
io_data_t *in = io_buffer_create(true);
- in->fd = 3;
+ in->fd = 3;
- escaped_separator = escape( COMPLETE_SEP_STR, 1);
+ escaped_separator = escape( COMPLETE_SEP_STR, 1);
+
+ for( size_t i=0; i< comp.size(); i++ )
+ {
+ const completion_t &el = comp.at( i );
+ has_case_sensitive |= !(el.flags & COMPLETE_NO_CASE );
+ }
+
+ for( size_t i=0; i< comp.size(); i++ )
+ {
- for( size_t i=0; i< comp.size(); i++ )
- {
- const completion_t &el = comp.at( i );
- has_case_sensitive |= !(el.flags & COMPLETE_NO_CASE );
- }
+ long base_len=-1;
+ const completion_t &el = comp.at( i );
- for( size_t i=0; i< comp.size(); i++ )
- {
+ wcstring completion_text;
+ wcstring description_text;
- long base_len=-1;
- const completion_t &el = comp.at( i );
-
- wcstring completion_text;
- wcstring description_text;
-
- if( has_case_sensitive && (el.flags & COMPLETE_NO_CASE ))
- {
- continue;
- }
-
- // Note that an empty completion is perfectly sensible here, e.g. tab-completing 'foo' with a file called 'foo' and another called 'foobar'
- if( el.flags & COMPLETE_NO_CASE )
- {
- if( base_len == -1 )
+ if( has_case_sensitive && (el.flags & COMPLETE_NO_CASE ))
+ {
+ continue;
+ }
+
+ // Note that an empty completion is perfectly sensible here, e.g. tab-completing 'foo' with a file called 'foo' and another called 'foobar'
+ if( el.flags & COMPLETE_NO_CASE )
+ {
+ if( base_len == -1 )
{
const wchar_t *begin, *buff = data->command_line.c_str();
-
+
parse_util_token_extent( buff, data->buff_pos, &begin, 0, 0, 0 );
base_len = data->buff_pos - (begin-buff);
}
-
- completion_text = escape_string( el.completion.c_str() + base_len, ESCAPE_ALL | ESCAPE_NO_QUOTED );
- }
- else
+
+ completion_text = escape_string( el.completion.c_str() + base_len, ESCAPE_ALL | ESCAPE_NO_QUOTED );
+ }
+ else
{
- completion_text = escape_string( el.completion, ESCAPE_ALL | ESCAPE_NO_QUOTED );
+ completion_text = escape_string( el.completion, ESCAPE_ALL | ESCAPE_NO_QUOTED );
}
-
-
- if( ! el.description.empty() )
- {
- description_text = escape_string( el.description, true );
- }
+
+
+ if( ! el.description.empty() )
+ {
+ description_text = escape_string( el.description, true );
+ }
/* It's possible (even common) to have an empty completion with no description. An example would be completing 'foo' with extant files 'foo' and 'foobar'. But fish_pager ignores blank lines. So if our completion text is empty, always include a description, even if it's empty.
*/
@@ -1052,44 +1056,44 @@ static void run_pager( const wcstring &prefix, int is_quoted, const std::vector<
msg.push_back(L'\n');
}
- free( escaped_separator );
-
- foo = wcs2str(msg.c_str());
- in->out_buffer_append(foo, strlen(foo) );
- free( foo );
-
- term_donate();
-
- io_data_t *out = io_buffer_create( false );
- out->fd = 4;
-
+ free( escaped_separator );
+
+ foo = wcs2str(msg.c_str());
+ in->out_buffer_append(foo, strlen(foo) );
+ free( foo );
+
+ term_donate();
+
+ io_data_t *out = io_buffer_create( false );
+ out->fd = 4;
+
parser_t &parser = parser_t::principal_parser();
io_chain_t io_chain;
io_chain.push_back(out);
io_chain.push_back(in);
- parser.eval( cmd, io_chain, TOP);
- term_steal();
+ parser.eval( cmd, io_chain, TOP);
+ term_steal();
- io_buffer_read( out );
+ io_buffer_read( out );
- int nil=0;
+ int nil=0;
out->out_buffer_append((char *)&nil, 1);
- wchar_t *tmp;
- wchar_t *str = str2wcs(out->out_buffer_ptr());
+ wchar_t *tmp;
+ wchar_t *str = str2wcs(out->out_buffer_ptr());
- if( str )
- {
- for( tmp = str + wcslen(str)-1; tmp >= str; tmp-- )
- {
- input_unreadch( *tmp );
- }
- free( str );
- }
+ if( str )
+ {
+ for( tmp = str + wcslen(str)-1; tmp >= str; tmp-- )
+ {
+ input_unreadch( *tmp );
+ }
+ free( str );
+ }
- io_buffer_destroy( out);
- io_buffer_destroy( in);
+ io_buffer_destroy( out);
+ io_buffer_destroy( in);
}
struct autosuggestion_context_t {
@@ -1102,10 +1106,10 @@ struct autosuggestion_context_t {
const env_vars_snapshot_t vars;
wcstring_list_t commands_to_load;
const unsigned int generation_count;
-
+
// don't reload more than once
bool has_tried_reloading;
-
+
autosuggestion_context_t(history_t *history, const wcstring &term, size_t pos) :
search_string(term),
cursor_pos(pos),
@@ -1117,28 +1121,28 @@ struct autosuggestion_context_t {
has_tried_reloading(false)
{
}
-
+
/* The function run in the background thread to determine an autosuggestion */
int threaded_autosuggest(void) {
ASSERT_IS_BACKGROUND_THREAD();
-
+
/* If the main thread has moved on, skip all the work */
if (generation_count != s_generation_count) {
return 0;
}
-
+
/* Let's make sure we aren't using the empty string */
if (search_string.empty()) {
return 0;
}
-
+
while (searcher.go_backwards()) {
history_item_t item = searcher.current_item();
-
+
/* Skip items with newlines because they make terrible autosuggestions */
if (item.str().find('\n') != wcstring::npos)
continue;
-
+
if (autosuggest_validate_from_history(item, detector, working_directory, vars)) {
/* The command autosuggestion was handled specially, so we're done */
this->autosuggestion = searcher.current_string();
@@ -1146,14 +1150,14 @@ struct autosuggestion_context_t {
}
}
-
+
/* Try handling a special command like cd */
wcstring special_suggestion;
if (autosuggest_suggest_special(search_string, working_directory, special_suggestion)) {
this->autosuggestion = special_suggestion;
return 1;
}
-
+
// Here we do something a little funny
// If the line ends with a space, and the cursor is not at the end,
// don't use completion autosuggestions. It ends up being pretty weird seeing stuff get spammed on the right
@@ -1176,7 +1180,7 @@ struct autosuggestion_context_t {
this->autosuggestion = completion_apply_to_command_line(comp.completion.c_str(), comp.flags, this->search_string, &cursor);
return 1;
}
-
+
return 0;
}
};
@@ -1198,7 +1202,7 @@ static void autosuggest_completed(autosuggestion_context_t *ctx, int result) {
/* Extract the commands to load */
wcstring_list_t commands_to_load;
ctx->commands_to_load.swap(commands_to_load);
-
+
/* If we have autosuggestions to load, load them and try again */
if (! result && ! commands_to_load.empty() && ! ctx->has_tried_reloading)
{
@@ -1210,7 +1214,7 @@ static void autosuggest_completed(autosuggestion_context_t *ctx, int result) {
iothread_perform(threaded_autosuggest, autosuggest_completed, ctx);
return;
}
-
+
if (result &&
can_autosuggest() &&
ctx->search_string == data->command_line &&
@@ -1237,7 +1241,7 @@ static void update_autosuggestion(void) {
}
#else
data->autosuggestion.clear();
- if (! data->suppress_autosuggestion && ! data->command_line.empty() && data->history_search.is_at_end()) {
+ if (data->allow_autosuggestion && ! data->suppress_autosuggestion && ! data->command_line.empty() && data->history_search.is_at_end()) {
autosuggestion_context_t *ctx = new autosuggestion_context_t(data->history, data->command_line, data->buff_pos);
iothread_perform(threaded_autosuggest, autosuggest_completed, ctx);
}
@@ -1263,22 +1267,22 @@ static void accept_autosuggestion(void) {
*/
static void reader_flash()
{
- struct timespec pollint;
+ struct timespec pollint;
- for( size_t i=0; ibuff_pos; i++ )
- {
- data->colors.at(i) = HIGHLIGHT_SEARCH_MATCH<<16;
- }
+ for( size_t i=0; ibuff_pos; i++ )
+ {
+ data->colors.at(i) = HIGHLIGHT_SEARCH_MATCH<<16;
+ }
+
+ reader_repaint();
+
+ pollint.tv_sec = 0;
+ pollint.tv_nsec = 100 * 1000000;
+ nanosleep( &pollint, NULL );
- reader_repaint();
-
- pollint.tv_sec = 0;
- pollint.tv_nsec = 100 * 1000000;
- nanosleep( &pollint, NULL );
-
- reader_super_highlight_me_plenty( data->buff_pos );
-
- reader_repaint();
+ reader_super_highlight_me_plenty( data->buff_pos );
+
+ reader_repaint();
}
/**
@@ -1299,23 +1303,23 @@ static void reader_flash()
static bool reader_can_replace( const wcstring &in, int flags )
{
- const wchar_t * str = in.c_str();
+ const wchar_t * str = in.c_str();
- if( flags & COMPLETE_DONT_ESCAPE )
- {
- return true;
- }
- /*
- Test characters that have a special meaning in any character position
- */
- while( *str )
- {
- if( wcschr( REPLACE_UNCLEAN, *str ) )
- return false;
- str++;
- }
+ if( flags & COMPLETE_DONT_ESCAPE )
+ {
+ return true;
+ }
+ /*
+ Test characters that have a special meaning in any character position
+ */
+ while( *str )
+ {
+ if( wcschr( REPLACE_UNCLEAN, *str ) )
+ return false;
+ str++;
+ }
- return true;
+ return true;
}
/* Compare two completions, except make the case insensitive comes larger than everyone (so they come last) */
@@ -1350,14 +1354,14 @@ static const completion_t *cycle_competions(const std::vector &com
{
/* Bump the index */
idx = (idx + 1) % size;
-
+
/* Bail if we've looped */
if (idx == start_idx)
break;
-
+
/* Get the completion */
const completion_t &c = comp.at(idx);
-
+
/* Try this completion */
if (! c.is_case_insensitive() || reader_can_replace(command_line, c.flags))
{
@@ -1366,14 +1370,14 @@ static const completion_t *cycle_competions(const std::vector &com
break;
}
}
-
+
*inout_idx = idx;
return result;
}
/**
Handle the list of completions. This means the following:
-
+
- If the list is empty, flash the terminal.
- If the list contains one element, write the whole element, and if
the element does not end on a '/', '@', ':', or a '=', also write a trailing
@@ -1382,199 +1386,199 @@ static const completion_t *cycle_competions(const std::vector &com
the prefix.
- If the list contains multiple elements without.
a common prefix, call run_pager to display a list of completions. Depending on terminal size and the length of the list, run_pager may either show less than a screenfull and exit or use an interactive pager to allow the user to scroll through the completions.
-
+
\param comp the list of completion strings
-
+
Return true if we inserted text into the command line, false if we did not.
*/
static bool handle_completions( const std::vector &comp )
{
- wchar_t *base = NULL;
- size_t len = 0;
- bool done = false;
+ wchar_t *base = NULL;
+ size_t len = 0;
+ bool done = false;
bool success = false;
- int count = 0;
- int flags=0;
- const wchar_t *begin, *end, *buff = data->command_line.c_str();
-
- parse_util_token_extent( buff, data->buff_pos, &begin, 0, 0, 0 );
- end = buff+data->buff_pos;
-
+ int count = 0;
+ int flags=0;
+ const wchar_t *begin, *end, *buff = data->command_line.c_str();
+
+ parse_util_token_extent( buff, data->buff_pos, &begin, 0, 0, 0 );
+ end = buff+data->buff_pos;
+
const wcstring tok(begin, end - begin);
-
- /*
- Check trivial cases
- */
- switch(comp.size())
- {
- /* No suitable completions found, flash screen and return */
- case 0:
- {
- reader_flash();
- done = true;
+
+ /*
+ Check trivial cases
+ */
+ switch(comp.size())
+ {
+ /* No suitable completions found, flash screen and return */
+ case 0:
+ {
+ reader_flash();
+ done = true;
success = false;
- break;
- }
+ break;
+ }
- /* Exactly one suitable completion found - insert it */
- case 1:
- {
+ /* Exactly one suitable completion found - insert it */
+ case 1:
+ {
+
+ const completion_t &c = comp.at( 0 );
+
+ /*
+ If this is a replacement completion, check
+ that we know how to replace it, e.g. that
+ the token doesn't contain evil operators
+ like {}
+ */
+ if( ! c.is_case_insensitive() || reader_can_replace( tok, c.flags ) )
+ {
+ completion_insert( c.completion.c_str(), c.flags );
+ }
+ done = true;
+ success = true;
+ break;
+ }
+ }
+
+
+ if( !done )
+ {
+ /* Try to find something to insert with the correct case */
+ for( size_t i=0; i< comp.size() ; i++ )
+ {
+ const completion_t &c = comp.at( i );
- const completion_t &c = comp.at( 0 );
-
- /*
- If this is a replacement completion, check
- that we know how to replace it, e.g. that
- the token doesn't contain evil operators
- like {}
- */
- if( ! c.is_case_insensitive() || reader_can_replace( tok, c.flags ) )
- {
- completion_insert( c.completion.c_str(), c.flags );
- }
- done = true;
- success = true;
- break;
- }
- }
-
-
- if( !done )
- {
- /* Try to find something to insert with the correct case */
- for( size_t i=0; i< comp.size() ; i++ )
- {
- const completion_t &c = comp.at( i );
-
- /* Ignore case insensitive completions for now */
- if( c.is_case_insensitive() )
- continue;
-
- count++;
-
- if( base )
- {
- size_t new_len = comp_len( base, c.completion.c_str() );
+ /* Ignore case insensitive completions for now */
+ if( c.is_case_insensitive() )
+ continue;
+
+ count++;
+
+ if( base )
+ {
+ size_t new_len = comp_len( base, c.completion.c_str() );
len = mini(new_len, len);
- }
- else
- {
- base = wcsdup( c.completion.c_str() );
- len = wcslen( base );
- flags = c.flags;
- }
- }
+ }
+ else
+ {
+ base = wcsdup( c.completion.c_str() );
+ len = wcslen( base );
+ flags = c.flags;
+ }
+ }
- /* If we found something to insert, do it. */
- if( len > 0 )
- {
- if( count > 1 )
- flags = flags | COMPLETE_NO_SPACE;
+ /* If we found something to insert, do it. */
+ if( len > 0 )
+ {
+ if( count > 1 )
+ flags = flags | COMPLETE_NO_SPACE;
- base[len]=L'\0';
- completion_insert(base, flags);
- done = true;
+ base[len]=L'\0';
+ completion_insert(base, flags);
+ done = true;
success = true;
- }
- }
+ }
+ }
+
+
+ if( !done && base == NULL )
+ {
+ /* Try to find something to insert ignoring case */
+ if( begin )
+ {
+ size_t offset = tok.size();
+
+ count = 0;
+
+ for( size_t i=0; i< comp.size(); i++ )
+ {
+ const completion_t &c = comp.at( i );
+ if( ! c.is_case_insensitive() )
+ continue;
+
+ if( !reader_can_replace( tok, c.flags ) )
+ {
+ len=0;
+ break;
+ }
- if( !done && base == NULL )
- {
- /* Try to find something to insert ignoring case */
- if( begin )
- {
- size_t offset = tok.size();
+ count++;
- count = 0;
+ if( base )
+ {
+ size_t new_len = offset + comp_ilen( base+offset, c.completion.c_str()+offset );
+ len = new_len < len ? new_len: len;
+ }
+ else
+ {
+ base = wcsdup( c.completion.c_str() );
+ len = wcslen( base );
+ flags = c.flags;
+
+ }
+ }
- for( size_t i=0; i< comp.size(); i++ )
- {
- const completion_t &c = comp.at( i );
-
- if( ! c.is_case_insensitive() )
- continue;
-
- if( !reader_can_replace( tok, c.flags ) )
- {
- len=0;
- break;
- }
-
- count++;
-
- if( base )
- {
- size_t new_len = offset + comp_ilen( base+offset, c.completion.c_str()+offset );
- len = new_len < len ? new_len: len;
- }
- else
- {
- base = wcsdup( c.completion.c_str() );
- len = wcslen( base );
- flags = c.flags;
-
- }
- }
-
- if( len > offset )
- {
- if( count > 1 )
- flags = flags | COMPLETE_NO_SPACE;
-
- base[len]=L'\0';
- completion_insert( base, flags );
- done = 1;
+ if( len > offset )
+ {
+ if( count > 1 )
+ flags = flags | COMPLETE_NO_SPACE;
+
+ base[len]=L'\0';
+ completion_insert( base, flags );
+ done = 1;
success = true;
- }
+ }
+
+ }
+ }
+
+ free( base );
- }
- }
+ if( !done )
+ {
+ /*
+ There is no common prefix in the completions, and show_list
+ is true, so we print the list
+ */
+ size_t len, prefix_start = 0;
+ wcstring prefix;
+ parse_util_get_parameter_info(data->command_line, data->buff_pos, NULL, &prefix_start, NULL);
- free( base );
+ assert(data->buff_pos >= prefix_start);
+ len = data->buff_pos - prefix_start;
- if( !done )
- {
- /*
- There is no common prefix in the completions, and show_list
- is true, so we print the list
- */
- size_t len, prefix_start = 0;
- wcstring prefix;
- parse_util_get_parameter_info(data->command_line, data->buff_pos, NULL, &prefix_start, NULL);
-
- assert(data->buff_pos >= prefix_start);
- len = data->buff_pos - prefix_start;
-
- if( len <= PREFIX_MAX_LEN )
+ if( len <= PREFIX_MAX_LEN )
{
prefix.append(data->command_line, prefix_start, len);
- }
- else
- {
+ }
+ else
+ {
// append just the end of the string
prefix = wcstring(&ellipsis_char, 1);
- prefix.append(data->command_line, prefix_start + len - PREFIX_MAX_LEN - 1, wcstring::npos);
+ prefix.append(data->command_line, prefix_start + len - PREFIX_MAX_LEN - 1, wcstring::npos);
}
- {
- int is_quoted;
+ {
+ int is_quoted;
- wchar_t quote;
- parse_util_get_parameter_info(data->command_line, data->buff_pos, "e, NULL, NULL);
- is_quoted = (quote != L'\0');
-
- write_loop(1, "\n", 1 );
-
- run_pager( prefix, is_quoted, comp );
- }
- s_reset( &data->screen, true);
- reader_repaint();
+ wchar_t quote;
+ parse_util_get_parameter_info(data->command_line, data->buff_pos, "e, NULL, NULL);
+ is_quoted = (quote != L'\0');
+
+ write_loop(1, "\n", 1 );
+
+ run_pager( prefix, is_quoted, comp );
+ }
+ s_reset( &data->screen, true);
+ reader_repaint();
success = false;
- }
- return success;
+ }
+ return success;
}
@@ -1583,101 +1587,102 @@ static bool handle_completions( const std::vector &comp )
*/
static void reader_interactive_init()
{
- /* See if we are running interactively. */
- pid_t shell_pgid;
+ /* See if we are running interactively. */
+ pid_t shell_pgid;
- input_init();
- kill_init();
- shell_pgid = getpgrp ();
+ input_init();
+ kill_init();
+ shell_pgid = getpgrp ();
- /*
- This should enable job control on fish, even if our parent process did
- not enable it for us.
- */
+ /*
+ This should enable job control on fish, even if our parent process did
+ not enable it for us.
+ */
- /*
- Check if we are in control of the terminal, so that we don't do
- semi-expensive things like reset signal handlers unless we
- really have to, which we often don't.
- */
- if (tcgetpgrp( 0 ) != shell_pgid)
- {
- int block_count = 0;
- int i;
+ /*
+ Check if we are in control of the terminal, so that we don't do
+ semi-expensive things like reset signal handlers unless we
+ really have to, which we often don't.
+ */
+ if (tcgetpgrp( 0 ) != shell_pgid)
+ {
+ int block_count = 0;
+ int i;
+
+ /*
+ Bummer, we are not in control of the terminal. Stop until
+ parent has given us control of it. Stopping in fish is a bit
+ of a challange, what with all the signal fidgeting, we need
+ to reset a bunch of signal state, making this coda a but
+ unobvious.
- /*
- Bummer, we are not in control of the terminal. Stop until
- parent has given us control of it. Stopping in fish is a bit
- of a challange, what with all the signal fidgeting, we need
- to reset a bunch of signal state, making this coda a but
- unobvious.
+ In theory, reseting signal handlers could cause us to miss
+ signal deliveries. In practice, this code should only be run
+ suring startup, when we're not waiting for any signals.
+ */
+ while (signal_is_blocked())
+ {
+ signal_unblock();
+ block_count++;
+ }
+ signal_reset_handlers();
+
+ /*
+ Ok, signal handlers are taken out of the picture. Stop ourself in a loop
+ until we are in control of the terminal.
+ */
+ while (tcgetpgrp( 0 ) != shell_pgid)
+ {
+ killpg( shell_pgid, SIGTTIN);
+ }
+
+ signal_set_handlers();
- In theory, reseting signal handlers could cause us to miss
- signal deliveries. In practice, this code should only be run
- suring startup, when we're not waiting for any signals.
- */
- while (signal_is_blocked())
- {
- signal_unblock();
- block_count++;
- }
- signal_reset_handlers();
+ for( i=0; ibuff_pos <= data->command_length() ))
- sanity_lose();
+ if( get_is_interactive())
+ {
+ if( !data )
+ sanity_lose();
+ if(!( data->buff_pos <= data->command_length() ))
+ sanity_lose();
+
if (data->colors.size() != data->command_length())
sanity_lose();
-
+
if (data->indents.size() != data->command_length())
sanity_lose();
-
- }
+
+ }
}
/**
@@ -1727,22 +1732,22 @@ static void set_command_line_and_position( const wcstring &new_str, size_t pos )
void reader_replace_current_token( const wchar_t *new_token )
{
- const wchar_t *begin, *end;
- size_t new_pos;
+ const wchar_t *begin, *end;
+ size_t new_pos;
- /* Find current token */
+ /* Find current token */
const wchar_t *buff = data->command_line.c_str();
- parse_util_token_extent( (wchar_t *)buff, data->buff_pos, &begin, &end, 0, 0 );
+ parse_util_token_extent( (wchar_t *)buff, data->buff_pos, &begin, &end, 0, 0 );
- if( !begin || !end )
- return;
+ if( !begin || !end )
+ return;
- /* Make new string */
+ /* Make new string */
wcstring new_buff(buff, begin - buff);
new_buff.append(new_token);
new_buff.append(end);
- new_pos = (begin-buff) + wcslen(new_token);
-
+ new_pos = (begin-buff) + wcslen(new_token);
+
set_command_line_and_position(new_buff, new_pos);
}
@@ -1752,21 +1757,21 @@ void reader_replace_current_token( const wchar_t *new_token )
*/
static void reset_token_history()
{
- const wchar_t *begin, *end;
+ const wchar_t *begin, *end;
const wchar_t *buff = data->command_line.c_str();
- parse_util_token_extent( (wchar_t *)buff, data->buff_pos, &begin, &end, 0, 0 );
-
- data->search_buff.clear();
- if( begin )
- {
+ parse_util_token_extent( (wchar_t *)buff, data->buff_pos, &begin, &end, 0, 0 );
+
+ data->search_buff.clear();
+ if( begin )
+ {
data->search_buff.append(begin, end - begin);
- }
+ }
- data->token_history_pos = -1;
- data->search_pos=0;
+ data->token_history_pos = -1;
+ data->search_pos=0;
data->search_prev.clear();
data->search_prev.push_back(data->search_buff);
-
+
data->history_search = history_search_t(*data->history, data->search_buff, HISTORY_SEARCH_TYPE_CONTAINS);
}
@@ -1782,128 +1787,128 @@ static void handle_token_history( int forward, int reset )
/* Paranoia */
if (! data)
return;
+
+ const wchar_t *str=0;
+ long current_pos;
+ tokenizer tok;
- const wchar_t *str=0;
- long current_pos;
- tokenizer tok;
+ if( reset )
+ {
+ /*
+ Start a new token search using the current token
+ */
+ reset_token_history();
- if( reset )
- {
- /*
- Start a new token search using the current token
- */
- reset_token_history();
-
- }
+ }
- current_pos = data->token_history_pos;
+ current_pos = data->token_history_pos;
- if( forward || data->search_pos + 1 < data->search_prev.size() )
- {
- if( forward )
- {
- if( data->search_pos > 0 )
- {
- data->search_pos--;
- }
+ if( forward || data->search_pos + 1 < data->search_prev.size() )
+ {
+ if( forward )
+ {
+ if( data->search_pos > 0 )
+ {
+ data->search_pos--;
+ }
str = data->search_prev.at(data->search_pos).c_str();
- }
- else
- {
- data->search_pos++;
+ }
+ else
+ {
+ data->search_pos++;
str = data->search_prev.at(data->search_pos).c_str();
- }
+ }
- reader_replace_current_token( str );
- reader_super_highlight_me_plenty( data->buff_pos );
- reader_repaint();
- }
- else
- {
- if( current_pos == -1 )
- {
+ reader_replace_current_token( str );
+ reader_super_highlight_me_plenty( data->buff_pos );
+ reader_repaint();
+ }
+ else
+ {
+ if( current_pos == -1 )
+ {
data->token_history_buff.clear();
-
- /*
- Search for previous item that contains this substring
- */
+
+ /*
+ Search for previous item that contains this substring
+ */
if (data->history_search.go_backwards()) {
wcstring item = data->history_search.current_string();
data->token_history_buff = data->history_search.current_string();
}
- current_pos = data->token_history_buff.size();
+ current_pos = data->token_history_buff.size();
- }
+ }
- if( data->token_history_buff.empty() )
- {
- /*
- We have reached the end of the history - check if the
- history already contains the search string itself, if so
- return, otherwise add it.
- */
+ if( data->token_history_buff.empty() )
+ {
+ /*
+ We have reached the end of the history - check if the
+ history already contains the search string itself, if so
+ return, otherwise add it.
+ */
- const wcstring &last = data->search_prev.back();
- if (data->search_buff != last)
- {
- str = wcsdup( data->search_buff.c_str() );
- }
- else
- {
- return;
- }
- }
- else
- {
+ const wcstring &last = data->search_prev.back();
+ if (data->search_buff != last)
+ {
+ str = wcsdup( data->search_buff.c_str() );
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
- //debug( 3, L"new '%ls'", data->token_history_buff.c_str() );
+ //debug( 3, L"new '%ls'", data->token_history_buff.c_str() );
- for( tok_init( &tok, data->token_history_buff.c_str(), TOK_ACCEPT_UNFINISHED );
- tok_has_next( &tok);
- tok_next( &tok ))
- {
- switch( tok_last_type( &tok ) )
- {
- case TOK_STRING:
- {
- if( wcsstr( tok_last( &tok ), data->search_buff.c_str() ) )
- {
- //debug( 3, L"Found token at pos %d\n", tok_get_pos( &tok ) );
- if( tok_get_pos( &tok ) >= current_pos )
- {
- break;
- }
- //debug( 3, L"ok pos" );
+ for( tok_init( &tok, data->token_history_buff.c_str(), TOK_ACCEPT_UNFINISHED );
+ tok_has_next( &tok);
+ tok_next( &tok ))
+ {
+ switch( tok_last_type( &tok ) )
+ {
+ case TOK_STRING:
+ {
+ if( wcsstr( tok_last( &tok ), data->search_buff.c_str() ) )
+ {
+ //debug( 3, L"Found token at pos %d\n", tok_get_pos( &tok ) );
+ if( tok_get_pos( &tok ) >= current_pos )
+ {
+ break;
+ }
+ //debug( 3, L"ok pos" );
const wcstring last_tok = tok_last( &tok );
if (find(data->search_prev.begin(), data->search_prev.end(), last_tok) == data->search_prev.end()) {
- data->token_history_pos = tok_get_pos( &tok );
- str = wcsdup(tok_last( &tok ));
- }
+ data->token_history_pos = tok_get_pos( &tok );
+ str = wcsdup(tok_last( &tok ));
+ }
- }
- }
- }
- }
+ }
+ }
+ }
+ }
- tok_destroy( &tok );
- }
+ tok_destroy( &tok );
+ }
- if( str )
- {
- reader_replace_current_token( str );
- reader_super_highlight_me_plenty( data->buff_pos );
- reader_repaint();
+ if( str )
+ {
+ reader_replace_current_token( str );
+ reader_super_highlight_me_plenty( data->buff_pos );
+ reader_repaint();
data->search_pos = data->search_prev.size();
data->search_prev.push_back(str);
- }
- else if( ! reader_interrupted() )
- {
- data->token_history_pos=-1;
- handle_token_history( 0, 0 );
- }
- }
+ }
+ else if( ! reader_interrupted() )
+ {
+ data->token_history_pos=-1;
+ handle_token_history( 0, 0 );
+ }
+ }
}
/* Our state machine that implements "one word" movement or erasure. */
@@ -1915,13 +1920,13 @@ class move_word_state_machine_t
s_alphanumeric_or_punctuation_except_slash,
s_end
} state;
-
+
public:
-
+
move_word_state_machine_t() : state(s_whitespace)
{
}
-
+
bool consume_char(wchar_t c)
{
/* Note fall-through in all of these! */
@@ -1931,20 +1936,20 @@ class move_word_state_machine_t
if (iswspace(c))
return true;
state = s_punctuation;
-
+
case s_punctuation:
if (iswpunct(c))
return true;
state = s_alphanumeric_or_punctuation_except_slash;
-
+
case s_alphanumeric_or_punctuation_except_slash:
if (c != L'/' && (iswalnum(c) || iswpunct(c)))
return true;
state = s_end;
-
+
case s_end:
default:
- return false;
+ return false;
}
}
};
@@ -1957,13 +1962,13 @@ class move_word_state_machine_t
\param dir Direction to move/erase. 0 means move left, 1 means move right.
\param erase Whether to erase the characters along the way or only move past them.
\param new if the new kill item should be appended to the previous kill item or not.
-
+
The regex we implement:
-
+
WHITESPACE*
PUNCTUATION*
ALPHANUMERIC_OR_PUNCTUATION_EXCEPT_SLASH*
-
+
Interesting test case:
/foo/bar/baz/ -> /foo/bar/ -> /foo/ -> /
echo --foo --bar -> echo --foo -> echo
@@ -1975,26 +1980,26 @@ enum move_word_dir_t {
static void move_word( bool move_right, bool erase, bool newv )
{
const size_t start_buff_pos = data->buff_pos;
- size_t end_buff_pos = data->buff_pos; //this is the last character we delete; we always delete at least one character
+ size_t end_buff_pos = data->buff_pos; //this is the last character we delete; we always delete at least one character
- /* Return if we are already at the edge */
+ /* Return if we are already at the edge */
const size_t boundary = move_right ? data->command_length() : 0;
if (data->buff_pos == boundary)
return;
-
- /*
- If we are beyond the last character and moving left, start by
- moving one step, since otherwise we'll start on the \0, which
- should be ignored.
- */
- if (! move_right && (end_buff_pos == data->command_length()) )
- {
- if( !end_buff_pos )
- return;
-
- end_buff_pos--;
- }
-
+
+ /*
+ If we are beyond the last character and moving left, start by
+ moving one step, since otherwise we'll start on the \0, which
+ should be ignored.
+ */
+ if (! move_right && (end_buff_pos == data->command_length()) )
+ {
+ if( !end_buff_pos )
+ return;
+
+ end_buff_pos--;
+ }
+
const wchar_t * const command_line = data->command_line.c_str();
move_word_state_machine_t state;
const size_t last_valid_end_buff_pos = (move_right ? data->command_length() - 1 : 0);
@@ -2007,132 +2012,132 @@ static void move_word( bool move_right, bool erase, bool newv )
end_buff_pos = next_buff_pos;
}
- if( erase )
- {
+ if( erase )
+ {
size_t start_idx = mini(start_buff_pos, end_buff_pos); //first char to delete
size_t end_idx = maxi(start_buff_pos, end_buff_pos); //last char to delete
-
+
// Don't try to delete past the end
end_idx = mini(end_idx, data->command_length() - 1);
-
+
// Don't autosuggest after a kill
data->suppress_autosuggestion = true;
-
- reader_kill( start_idx, end_idx - start_idx + 1, move_right?KILL_APPEND:KILL_PREPEND, newv );
- }
- else
- {
- data->buff_pos = move_right ? end_buff_pos + 1 : end_buff_pos;
- reader_repaint();
- }
+
+ reader_kill( start_idx, end_idx - start_idx + 1, move_right?KILL_APPEND:KILL_PREPEND, newv );
+ }
+ else
+ {
+ data->buff_pos = move_right ? end_buff_pos + 1 : end_buff_pos;
+ reader_repaint();
+ }
}
const wchar_t *reader_get_buffer(void)
{
ASSERT_IS_MAIN_THREAD();
- return data?data->command_line.c_str():NULL;
+ return data?data->command_line.c_str():NULL;
}
history_t *reader_get_history(void) {
ASSERT_IS_MAIN_THREAD();
- return data ? data->history : NULL;
+ return data ? data->history : NULL;
}
void reader_set_buffer( const wcstring &b, size_t pos )
{
- if( !data )
- return;
+ if( !data )
+ return;
/* Callers like to pass us pointers into ourselves, so be careful! I don't know if we can use operator= with a pointer to our interior, so use an intermediate. */
- size_t command_line_len = b.size();
+ size_t command_line_len = b.size();
data->command_line = b;
data->command_line_changed();
/* Don't set a position past the command line length */
if (pos > command_line_len)
pos = command_line_len;
-
+
data->buff_pos = pos;
- data->search_mode = NO_SEARCH;
- data->search_buff.clear();
- data->history_search.go_to_end();
+ data->search_mode = NO_SEARCH;
+ data->search_buff.clear();
+ data->history_search.go_to_end();
- reader_super_highlight_me_plenty( data->buff_pos );
- reader_repaint_needed();
+ reader_super_highlight_me_plenty( data->buff_pos );
+ reader_repaint_needed();
}
size_t reader_get_cursor_pos()
{
- if( !data )
- return (size_t)(-1);
+ if( !data )
+ return (size_t)(-1);
- return data->buff_pos;
+ return data->buff_pos;
}
#define ENV_CMD_DURATION L"CMD_DURATION"
void set_env_cmd_duration(struct timeval *after, struct timeval *before)
{
- time_t secs = after->tv_sec - before->tv_sec;
- suseconds_t usecs = after->tv_usec - before->tv_usec;
- wchar_t buf[16];
+ time_t secs = after->tv_sec - before->tv_sec;
+ suseconds_t usecs = after->tv_usec - before->tv_usec;
+ wchar_t buf[16];
- if (after->tv_usec < before->tv_usec) {
- usecs += 1000000;
- secs -= 1;
- }
+ if (after->tv_usec < before->tv_usec) {
+ usecs += 1000000;
+ secs -= 1;
+ }
- if (secs < 1) {
- env_remove( ENV_CMD_DURATION, 0 );
- } else {
- if (secs < 10) { // 10 secs
- swprintf(buf, 16, L"%lu.%02us", secs, usecs / 10000);
- } else if (secs < 60) { // 1 min
- swprintf(buf, 16, L"%lu.%01us", secs, usecs / 100000);
- } else if (secs < 600) { // 10 mins
- swprintf(buf, 16, L"%lum %lu.%01us", secs / 60, secs % 60, usecs / 100000);
- } else if (secs < 5400) { // 1.5 hours
- swprintf(buf, 16, L"%lum %lus", secs / 60, secs % 60);
- } else {
- swprintf(buf, 16, L"%.1fh", secs / 3600.0);
- }
- env_set( ENV_CMD_DURATION, buf, ENV_EXPORT );
- }
+ if (secs < 1) {
+ env_remove( ENV_CMD_DURATION, 0 );
+ } else {
+ if (secs < 10) { // 10 secs
+ swprintf(buf, 16, L"%lu.%02us", secs, usecs / 10000);
+ } else if (secs < 60) { // 1 min
+ swprintf(buf, 16, L"%lu.%01us", secs, usecs / 100000);
+ } else if (secs < 600) { // 10 mins
+ swprintf(buf, 16, L"%lum %lu.%01us", secs / 60, secs % 60, usecs / 100000);
+ } else if (secs < 5400) { // 1.5 hours
+ swprintf(buf, 16, L"%lum %lus", secs / 60, secs % 60);
+ } else {
+ swprintf(buf, 16, L"%.1fh", secs / 3600.0);
+ }
+ env_set( ENV_CMD_DURATION, buf, ENV_EXPORT );
+ }
}
void reader_run_command( parser_t &parser, const wchar_t *cmd )
{
- wchar_t *ft;
- struct timeval time_before, time_after;
+ wchar_t *ft;
+ struct timeval time_before, time_after;
- ft= tok_first( cmd );
+ ft= tok_first( cmd );
- if( ft != 0 )
- env_set( L"_", ft, ENV_GLOBAL );
- free(ft);
+ if( ft != 0 )
+ env_set( L"_", ft, ENV_GLOBAL );
+ free(ft);
- reader_write_title();
+ reader_write_title();
- term_donate();
+ term_donate();
- gettimeofday(&time_before, NULL);
+ gettimeofday(&time_before, NULL);
- parser.eval( cmd, io_chain_t(), TOP );
- job_reap( 1 );
+ parser.eval( cmd, io_chain_t(), TOP );
+ job_reap( 1 );
- gettimeofday(&time_after, NULL);
- set_env_cmd_duration(&time_after, &time_before);
+ gettimeofday(&time_after, NULL);
+ set_env_cmd_duration(&time_after, &time_before);
- term_steal();
+ term_steal();
- env_set( L"_", program_name, ENV_GLOBAL );
+ env_set( L"_", program_name, ENV_GLOBAL );
#ifdef HAVE__PROC_SELF_STAT
- proc_update_jiffies();
+ proc_update_jiffies();
#endif
@@ -2141,16 +2146,16 @@ void reader_run_command( parser_t &parser, const wchar_t *cmd )
int reader_shell_test( const wchar_t *b )
{
- int res = parser_t::principal_parser().test( b, 0, 0, 0 );
+ int res = parser_t::principal_parser().test( b, 0, 0, 0 );
+
+ if( res & PARSER_TEST_ERROR )
+ {
+ wcstring sb;
- if( res & PARSER_TEST_ERROR )
- {
- wcstring sb;
-
- const int tmp[1] = {0};
- const int tmp2[1] = {0};
+ const int tmp[1] = {0};
+ const int tmp2[1] = {0};
const wcstring empty;
-
+
s_write( &data->screen,
empty,
empty,
@@ -2159,12 +2164,12 @@ int reader_shell_test( const wchar_t *b )
tmp,
tmp2,
0);
-
-
- parser_t::principal_parser().test( b, 0, &sb, L"fish" );
- fwprintf( stderr, L"%ls", sb.c_str() );
- }
- return res;
+
+
+ parser_t::principal_parser().test( b, 0, &sb, L"fish" );
+ fwprintf( stderr, L"%ls", sb.c_str() );
+ }
+ return res;
}
/**
@@ -2174,58 +2179,58 @@ int reader_shell_test( const wchar_t *b )
*/
static int default_test( const wchar_t *b )
{
- return 0;
+ return 0;
}
void reader_push( const wchar_t *name )
{
reader_data_t *n = new reader_data_t();
-
+
n->history = & history_t::history_with_name(name);
- n->app_name = name;
- n->next = data;
+ n->app_name = name;
+ n->next = data;
- data=n;
+ data=n;
- data->command_line_changed();
+ data->command_line_changed();
- if( data->next == 0 )
- {
- reader_interactive_init();
- }
+ if( data->next == 0 )
+ {
+ reader_interactive_init();
+ }
- exec_prompt();
- reader_set_highlight_function( &highlight_universal );
- reader_set_test_function( &default_test );
- reader_set_left_prompt( L"" );
+ exec_prompt();
+ reader_set_highlight_function( &highlight_universal );
+ reader_set_test_function( &default_test );
+ reader_set_left_prompt( L"" );
}
void reader_pop()
{
- reader_data_t *n = data;
+ reader_data_t *n = data;
- if( data == 0 )
- {
- debug( 0, _( L"Pop null reader block" ) );
- sanity_lose();
- return;
- }
-
- data=data->next;
+ if( data == 0 )
+ {
+ debug( 0, _( L"Pop null reader block" ) );
+ sanity_lose();
+ return;
+ }
+ data=data->next;
+
/* Invoke the destructor to balance our new */
delete n;
- if( data == 0 )
- {
- reader_interactive_destroy();
- }
- else
- {
- end_loop = 0;
- //history_set_mode( data->app_name.c_str() );
- s_reset( &data->screen, true);
- }
+ if( data == 0 )
+ {
+ reader_interactive_destroy();
+ }
+ else
+ {
+ end_loop = 0;
+ //history_set_mode( data->app_name.c_str() );
+ s_reset( &data->screen, true);
+ }
}
void reader_set_left_prompt( const wcstring &new_prompt )
@@ -2238,19 +2243,24 @@ void reader_set_right_prompt(const wcstring &new_prompt)
data->right_prompt = new_prompt;
}
+void reader_set_allow_autosuggesting(bool flag)
+{
+ data->allow_autosuggestion = flag;
+}
+
void reader_set_complete_function( complete_function_t f )
{
- data->complete_func = f;
+ data->complete_func = f;
}
void reader_set_highlight_function( highlight_function_t func )
{
- data->highlight_function = func;
+ data->highlight_function = func;
}
void reader_set_test_function( int (*f)( const wchar_t * ) )
{
- data->test_func = f;
+ data->test_func = f;
}
void reader_import_history_if_necessary(void)
@@ -2276,26 +2286,26 @@ void reader_import_history_if_necessary(void)
class background_highlight_context_t {
public:
/** The string to highlight */
- const wcstring string_to_highlight;
-
- /** Color buffer */
- std::vector colors;
-
- /** The position to use for bracket matching */
- const size_t match_highlight_pos;
-
- /** Function for syntax highlighting */
- const highlight_function_t highlight_function;
-
+ const wcstring string_to_highlight;
+
+ /** Color buffer */
+ std::vector colors;
+
+ /** The position to use for bracket matching */
+ const size_t match_highlight_pos;
+
+ /** Function for syntax highlighting */
+ const highlight_function_t highlight_function;
+
/** Environment variables */
const env_vars_snapshot_t vars;
/** When the request was made */
const double when;
-
+
/** Gen count at the time the request was made */
const unsigned int generation_count;
-
+
background_highlight_context_t(const wcstring &pbuff, size_t phighlight_pos, highlight_function_t phighlight_func) :
string_to_highlight(pbuff),
colors(pbuff.size(), 0),
@@ -2306,7 +2316,7 @@ public:
generation_count(s_generation_count)
{
}
-
+
int threaded_highlight() {
if (generation_count != s_generation_count)
{
@@ -2323,41 +2333,41 @@ public:
/* Called to set the highlight flag for search results */
static void highlight_search(void) {
- if( ! data->search_buff.empty() && ! data->history_search.is_at_end())
- {
+ if( ! data->search_buff.empty() && ! data->history_search.is_at_end())
+ {
const wchar_t *buff = data->command_line.c_str();
- const wchar_t *match = wcsstr( buff, data->search_buff.c_str() );
- if( match )
- {
- size_t start = match-buff;
- size_t i, count = data->search_buff.size();
- for( i=0; icolors.at(start+i) |= HIGHLIGHT_SEARCH_MATCH<<16;
- }
- }
- }
+ const wchar_t *match = wcsstr( buff, data->search_buff.c_str() );
+ if( match )
+ {
+ size_t start = match-buff;
+ size_t i, count = data->search_buff.size();
+ for( i=0; icolors.at(start+i) |= HIGHLIGHT_SEARCH_MATCH<<16;
+ }
+ }
+ }
}
static void highlight_complete(background_highlight_context_t *ctx, int result) {
ASSERT_IS_MAIN_THREAD();
- if (ctx->string_to_highlight == data->command_line) {
- /* The data hasn't changed, so swap in our colors. The colors may not have changed, so do nothing if they have not. */
+ if (ctx->string_to_highlight == data->command_line) {
+ /* The data hasn't changed, so swap in our colors. The colors may not have changed, so do nothing if they have not. */
assert(ctx->colors.size() == data->command_length());
if (data->colors != ctx->colors)
{
data->colors.swap(ctx->colors);
-
+
//data->repaint_needed = 1;
//s_reset( &data->screen, 1 );
-
+
sanity_check();
highlight_search();
reader_repaint();
}
- }
-
- /* Free our context */
+ }
+
+ /* Free our context */
delete ctx;
}
@@ -2378,11 +2388,11 @@ static int threaded_highlight(background_highlight_context_t *ctx) {
static void reader_super_highlight_me_plenty( size_t match_highlight_pos )
{
reader_sanity_check();
-
- background_highlight_context_t *ctx = new background_highlight_context_t(data->command_line, match_highlight_pos, data->highlight_function);
- iothread_perform(threaded_highlight, highlight_complete, ctx);
+
+ background_highlight_context_t *ctx = new background_highlight_context_t(data->command_line, match_highlight_pos, data->highlight_function);
+ iothread_perform(threaded_highlight, highlight_complete, ctx);
highlight_search();
-
+
/* Here's a hack. Check to see if our autosuggestion still applies; if so, don't recompute it. Since the autosuggestion computation is asynchronous, this avoids "flashing" as you type into the autosuggestion. */
const wcstring &cmd = data->command_line, &suggest = data->autosuggestion;
if (can_autosuggest() && ! suggest.empty() && string_prefixes_string_case_insensitive(cmd, suggest)) {
@@ -2395,10 +2405,10 @@ static void reader_super_highlight_me_plenty( size_t match_highlight_pos )
int exit_status()
{
- if( get_is_interactive() )
- return job_list_is_empty() && data->end_loop;
- else
- return end_loop;
+ if( get_is_interactive() )
+ return job_list_is_empty() && data->end_loop;
+ else
+ return end_loop;
}
/**
@@ -2409,136 +2419,135 @@ int exit_status()
static void handle_end_loop()
{
- job_t *j;
- int job_count=0;
- int is_breakpoint=0;
- block_t *b;
- parser_t &parser = parser_t::principal_parser();
-
- for( b = parser.current_block;
- b;
- b = b->outer )
- {
- if( b->type() == BREAKPOINT )
- {
- is_breakpoint = 1;
- break;
- }
- }
-
+ job_t *j;
+ int job_count=0;
+ int is_breakpoint=0;
+ block_t *b;
+ parser_t &parser = parser_t::principal_parser();
+
+ for( b = parser.current_block;
+ b;
+ b = b->outer )
+ {
+ if( b->type() == BREAKPOINT )
+ {
+ is_breakpoint = 1;
+ break;
+ }
+ }
+
job_iterator_t jobs;
while ((j = jobs.next()))
- {
- if( !job_is_completed(j) )
- {
- job_count++;
- break;
- }
- }
-
- if( !reader_exit_forced() && !data->prev_end_loop && job_count && !is_breakpoint )
- {
- writestr(_( L"There are stopped jobs. A second attempt to exit will enforce their termination.\n" ));
-
- reader_exit( 0, 0 );
- data->prev_end_loop=1;
- }
- else
- {
+ {
+ if( !job_is_completed(j) )
+ {
+ job_count++;
+ break;
+ }
+ }
+
+ if( !reader_exit_forced() && !data->prev_end_loop && job_count && !is_breakpoint )
+ {
+ writestr(_( L"There are stopped jobs. A second attempt to exit will enforce their termination.\n" ));
+
+ reader_exit( 0, 0 );
+ data->prev_end_loop=1;
+ }
+ else
+ {
/* PCA: we used to only hangup jobs if stdin was closed. This prevented child processes from exiting. It's unclear to my why it matters if stdin is closed, but it seems to me if we're forcing an exit, we definitely want to hang up our processes.
-
+
See https://github.com/fish-shell/fish-shell/issues/138
*/
- if( reader_exit_forced() || !isatty(0) )
- {
- /*
- We already know that stdin is a tty since we're
- in interactive mode. If isatty returns false, it
- means stdin must have been closed.
- */
- job_iterator_t jobs;
- while ((j = jobs.next()))
- {
- if( ! job_is_completed( j ) )
- {
- job_signal( j, SIGHUP );
- }
- }
- }
- }
+ if( reader_exit_forced() || !isatty(0) )
+ {
+ /*
+ We already know that stdin is a tty since we're
+ in interactive mode. If isatty returns false, it
+ means stdin must have been closed.
+ */
+ job_iterator_t jobs;
+ while ((j = jobs.next()))
+ {
+ if( ! job_is_completed( j ) )
+ {
+ job_signal( j, SIGHUP );
+ }
+ }
+ }
+ }
}
-
-
/**
Read interactively. Read input from stdin while providing editing
facilities.
*/
static int read_i()
{
- reader_push(L"fish");
- reader_set_complete_function( &complete );
- reader_set_highlight_function( &highlight_shell );
- reader_set_test_function( &reader_shell_test );
- reader_import_history_if_necessary();
+ reader_push(L"fish");
+ reader_set_complete_function( &complete );
+ reader_set_highlight_function( &highlight_shell );
+ reader_set_test_function( &reader_shell_test );
+ reader_set_allow_autosuggesting(true);
+ reader_import_history_if_necessary();
+
+ parser_t &parser = parser_t::principal_parser();
+
+ data->prev_end_loop=0;
- parser_t &parser = parser_t::principal_parser();
+ while( (!data->end_loop) && (!sanity_check()) )
+ {
+ const wchar_t *tmp;
- data->prev_end_loop=0;
+ event_fire_generic(L"fish_prompt");
+ if( function_exists( LEFT_PROMPT_FUNCTION_NAME ) )
+ reader_set_left_prompt( LEFT_PROMPT_FUNCTION_NAME );
+ else
+ reader_set_left_prompt( DEFAULT_PROMPT );
+
+ if( function_exists( RIGHT_PROMPT_FUNCTION_NAME ) )
+ reader_set_right_prompt( RIGHT_PROMPT_FUNCTION_NAME );
+ else
+ reader_set_right_prompt( L"" );
+
- while( (!data->end_loop) && (!sanity_check()) )
- {
- const wchar_t *tmp;
+ /*
+ Put buff in temporary string and clear buff, so
+ that we can handle a call to reader_set_buffer
+ during evaluation.
+ */
- event_fire_generic(L"fish_prompt");
- if( function_exists( LEFT_PROMPT_FUNCTION_NAME ) )
- reader_set_left_prompt( LEFT_PROMPT_FUNCTION_NAME );
- else
- reader_set_left_prompt( DEFAULT_PROMPT );
+
+ tmp = reader_readline();
+
- if( function_exists( RIGHT_PROMPT_FUNCTION_NAME ) )
- reader_set_right_prompt( RIGHT_PROMPT_FUNCTION_NAME );
- else
- reader_set_right_prompt( L"" );
-
-
- /*
- Put buff in temporary string and clear buff, so
- that we can handle a call to reader_set_buffer
- during evaluation.
- */
-
-
- tmp = reader_readline();
-
-
- if( data->end_loop)
- {
- handle_end_loop();
- }
- else if( tmp )
- {
- tmp = wcsdup( tmp );
-
- data->buff_pos=0;
+ if( data->end_loop)
+ {
+ handle_end_loop();
+ }
+ else if( tmp )
+ {
+ tmp = wcsdup( tmp );
+
+ data->buff_pos=0;
data->command_line.clear();
data->command_line_changed();
- reader_run_command( parser, tmp );
- free( (void *)tmp );
- if( data->end_loop)
- {
- handle_end_loop();
- }
- else
- {
- data->prev_end_loop=0;
- }
- }
+ reader_run_command( parser, tmp );
+ free( (void *)tmp );
+ if( data->end_loop)
+ {
+ handle_end_loop();
+ }
+ else
+ {
+ data->prev_end_loop=0;
+ }
+ }
+
-
- }
- reader_pop();
- return 0;
+ }
+ reader_pop();
+ return 0;
}
/**
@@ -2547,10 +2556,10 @@ static int read_i()
*/
static int can_read( int fd )
{
- struct timeval can_read_timeout = { 0, 0 };
- fd_set fds;
+ struct timeval can_read_timeout = { 0, 0 };
+ fd_set fds;
- FD_ZERO(&fds);
+ FD_ZERO(&fds);
FD_SET(fd, &fds);
return select(fd + 1, &fds, 0, 0, &can_read_timeout) == 1;
}
@@ -2561,7 +2570,7 @@ static int can_read( int fd )
*/
static int wchar_private( wchar_t c )
{
- return ( (c >= 0xe000) && (c <= 0xf8ff ) );
+ return ( (c >= 0xe000) && (c <= 0xf8ff ) );
}
/**
@@ -2570,191 +2579,191 @@ static int wchar_private( wchar_t c )
*/
static bool is_backslashed( const wchar_t *str, size_t pos )
{
- size_t count = 0;
- size_t idx = pos;
- while (idx--)
- {
- if( str[idx] != L'\\' )
- break;
+ size_t count = 0;
+ size_t idx = pos;
+ while (idx--)
+ {
+ if( str[idx] != L'\\' )
+ break;
+
+ count++;
+ }
- count++;
- }
-
- return (count % 2) == 1;
+ return (count % 2) == 1;
}
const wchar_t *reader_readline()
{
-
- wint_t c;
- int last_char=0;
+
+ wint_t c;
+ int last_char=0;
size_t yank_len=0;
- const wchar_t *yank_str;
- bool comp_empty = true;
- std::vector comp;
- int finished=0;
- struct termios old_modes;
+ const wchar_t *yank_str;
+ bool comp_empty = true;
+ std::vector comp;
+ int finished=0;
+ struct termios old_modes;
/* The cycle index in our completion list */
size_t completion_cycle_idx = (size_t)(-1);
-
+
/* The command line before completion */
wcstring cycle_command_line;
size_t cycle_cursor_pos;
-
- data->search_buff.clear();
- data->search_mode = NO_SEARCH;
-
-
- exec_prompt();
-
- reader_super_highlight_me_plenty( data->buff_pos );
- s_reset( &data->screen, true);
- reader_repaint();
-
- /*
+
+ data->search_buff.clear();
+ data->search_mode = NO_SEARCH;
+
+
+ exec_prompt();
+
+ reader_super_highlight_me_plenty( data->buff_pos );
+ s_reset( &data->screen, true);
+ reader_repaint();
+
+ /*
get the current terminal modes. These will be restored when the
function returns.
*/
- tcgetattr(0,&old_modes);
- /* set the new modes */
- if( tcsetattr(0,TCSANOW,&shell_modes))
- {
- wperror(L"tcsetattr");
+ tcgetattr(0,&old_modes);
+ /* set the new modes */
+ if( tcsetattr(0,TCSANOW,&shell_modes))
+ {
+ wperror(L"tcsetattr");
}
-
- while( !finished && !data->end_loop)
- {
- /*
+
+ while( !finished && !data->end_loop)
+ {
+ /*
Sometimes strange input sequences seem to generate a zero
byte. I believe these simply mean a character was pressed
but it should be ignored. (Example: Trying to add a tilde
(~) to digit)
*/
- while( 1 )
- {
- int was_interactive_read = is_interactive_read;
- is_interactive_read = 1;
- c=input_readch();
- is_interactive_read = was_interactive_read;
+ while( 1 )
+ {
+ int was_interactive_read = is_interactive_read;
+ is_interactive_read = 1;
+ c=input_readch();
+ is_interactive_read = was_interactive_read;
+
+ if( ( (!wchar_private(c))) && (c>31) && (c != 127) )
+ {
+ if( can_read(0) )
+ {
+
+ wchar_t arr[READAHEAD_MAX+1];
+ int i;
+
+ memset( arr, 0, sizeof( arr ) );
+ arr[0] = c;
+
+ for( i=1; i31) && (c != 127) )
+ {
+ arr[i]=c;
+ c=0;
+ }
+ else
+ break;
+ }
+
+ insert_string( arr );
+
+ }
+ }
+
+ if( c != 0 )
+ break;
+ }
- if( ( (!wchar_private(c))) && (c>31) && (c != 127) )
- {
- if( can_read(0) )
- {
-
- wchar_t arr[READAHEAD_MAX+1];
- int i;
-
- memset( arr, 0, sizeof( arr ) );
- arr[0] = c;
-
- for( i=1; i31) && (c != 127) )
- {
- arr[i]=c;
- c=0;
- }
- else
- break;
- }
-
- insert_string( arr );
-
- }
- }
-
- if( c != 0 )
- break;
- }
-
- if( last_char != R_YANK && last_char != R_YANK_POP )
- yank_len=0;
+ if( last_char != R_YANK && last_char != R_YANK_POP )
+ yank_len=0;
const wchar_t *buff = data->command_line.c_str();
- switch( c )
- {
-
+ switch( c )
+ {
+
/* go to beginning of line*/
- case R_BEGINNING_OF_LINE:
- {
- while( ( data->buff_pos>0 ) &&
+ case R_BEGINNING_OF_LINE:
+ {
+ while( ( data->buff_pos>0 ) &&
( buff[data->buff_pos-1] != L'\n' ) )
- {
- data->buff_pos--;
- }
-
- reader_repaint();
- break;
- }
-
- case R_END_OF_LINE:
- {
- while( buff[data->buff_pos] &&
+ {
+ data->buff_pos--;
+ }
+
+ reader_repaint();
+ break;
+ }
+
+ case R_END_OF_LINE:
+ {
+ while( buff[data->buff_pos] &&
buff[data->buff_pos] != L'\n' )
- {
- data->buff_pos++;
- }
-
- reader_repaint();
- break;
- }
-
-
- case R_BEGINNING_OF_BUFFER:
- {
- data->buff_pos = 0;
-
- reader_repaint();
- break;
- }
-
+ {
+ data->buff_pos++;
+ }
+
+ reader_repaint();
+ break;
+ }
+
+
+ case R_BEGINNING_OF_BUFFER:
+ {
+ data->buff_pos = 0;
+
+ reader_repaint();
+ break;
+ }
+
/* go to EOL*/
- case R_END_OF_BUFFER:
- {
- data->buff_pos = data->command_length();
-
- reader_repaint();
- break;
- }
-
- case R_NULL:
- {
- reader_repaint_if_needed();
- break;
- }
-
- case R_REPAINT:
- {
- exec_prompt();
- write_loop( 1, "\r", 1 );
- s_reset( &data->screen, false);
- reader_repaint();
- break;
- }
-
- case R_EOF:
- {
- exit_forced = 1;
- data->end_loop=1;
- break;
- }
-
+ case R_END_OF_BUFFER:
+ {
+ data->buff_pos = data->command_length();
+
+ reader_repaint();
+ break;
+ }
+
+ case R_NULL:
+ {
+ reader_repaint_if_needed();
+ break;
+ }
+
+ case R_REPAINT:
+ {
+ exec_prompt();
+ write_loop( 1, "\r", 1 );
+ s_reset( &data->screen, false);
+ reader_repaint();
+ break;
+ }
+
+ case R_EOF:
+ {
+ exit_forced = 1;
+ data->end_loop=1;
+ break;
+ }
+
/* complete */
- case R_COMPLETE:
- {
-
- if( !data->complete_func )
- break;
-
+ case R_COMPLETE:
+ {
+
+ if( !data->complete_func )
+ break;
+
if (! comp_empty && last_char == R_COMPLETE)
{
/* The user typed R_COMPLETE more than once in a row. Cycle through our available completions */
@@ -2764,541 +2773,541 @@ const wchar_t *reader_readline()
size_t cursor_pos = cycle_cursor_pos;
const wcstring new_cmd_line = completion_apply_to_command_line(next_comp->completion, next_comp->flags, cycle_command_line, &cursor_pos);
reader_set_buffer(new_cmd_line, cursor_pos);
-
+
/* Since we just inserted a completion, don't immediately do a new autosuggestion */
data->suppress_autosuggestion = true;
}
}
- else
- {
+ else
+ {
/* Either the user hit tab only once, or we had no visible completion list. */
- const wchar_t *begin, *end;
- const wchar_t *token_begin, *token_end;
+ const wchar_t *begin, *end;
+ const wchar_t *token_begin, *token_end;
const wchar_t *buff = data->command_line.c_str();
- long cursor_steps;
-
+ long cursor_steps;
+
/* Clear the completion list */
comp.clear();
-
- parse_util_cmdsubst_extent( buff, data->buff_pos, &begin, &end );
-
- parse_util_token_extent( begin, data->buff_pos - (begin-buff), &token_begin, &token_end, 0, 0 );
-
- cursor_steps = token_end - buff- data->buff_pos;
- data->buff_pos += cursor_steps;
- if( is_backslashed( buff, data->buff_pos ) )
- {
- remove_backward();
- }
-
- reader_repaint();
-
- size_t len = data->buff_pos - (begin-buff);
+
+ parse_util_cmdsubst_extent( buff, data->buff_pos, &begin, &end );
+
+ parse_util_token_extent( begin, data->buff_pos - (begin-buff), &token_begin, &token_end, 0, 0 );
+
+ cursor_steps = token_end - buff- data->buff_pos;
+ data->buff_pos += cursor_steps;
+ if( is_backslashed( buff, data->buff_pos ) )
+ {
+ remove_backward();
+ }
+
+ reader_repaint();
+
+ size_t len = data->buff_pos - (begin-buff);
const wcstring buffcpy = wcstring(begin, len);
-
- data->complete_func( buffcpy, comp, COMPLETE_DEFAULT, NULL);
-
- /* Munge our completions */
- sort(comp.begin(), comp.end());
- remove_duplicates( comp );
- prioritize_completions(comp);
-
- /* Record our cycle_command_line */
- cycle_command_line = data->command_line;
- cycle_cursor_pos = data->buff_pos;
-
- comp_empty = handle_completions( comp );
-
- /* Start the cycle at the beginning */
- completion_cycle_idx = (size_t)(-1);
- }
-
- break;
- }
-
+
+ data->complete_func( buffcpy, comp, COMPLETE_DEFAULT, NULL);
+
+ /* Munge our completions */
+ sort(comp.begin(), comp.end());
+ remove_duplicates( comp );
+ prioritize_completions(comp);
+
+ /* Record our cycle_command_line */
+ cycle_command_line = data->command_line;
+ cycle_cursor_pos = data->buff_pos;
+
+ comp_empty = handle_completions( comp );
+
+ /* Start the cycle at the beginning */
+ completion_cycle_idx = (size_t)(-1);
+ }
+
+ break;
+ }
+
/* kill */
- case R_KILL_LINE:
- {
+ case R_KILL_LINE:
+ {
const wchar_t *buff = data->command_line.c_str();
- const wchar_t *begin = &buff[data->buff_pos];
- const wchar_t *end = begin;
-
- while( *end && *end != L'\n' )
- end++;
-
- if( end==begin && *end )
- end++;
-
- size_t len = end-begin;
- if( len )
- {
- reader_kill( begin - buff, len, KILL_APPEND, last_char!=R_KILL_LINE );
- }
-
- break;
- }
-
- case R_BACKWARD_KILL_LINE:
- {
- if( data->buff_pos > 0 )
- {
+ const wchar_t *begin = &buff[data->buff_pos];
+ const wchar_t *end = begin;
+
+ while( *end && *end != L'\n' )
+ end++;
+
+ if( end==begin && *end )
+ end++;
+
+ size_t len = end-begin;
+ if( len )
+ {
+ reader_kill( begin - buff, len, KILL_APPEND, last_char!=R_KILL_LINE );
+ }
+
+ break;
+ }
+
+ case R_BACKWARD_KILL_LINE:
+ {
+ if( data->buff_pos > 0 )
+ {
const wchar_t *buff = data->command_line.c_str();
- const wchar_t *end = &buff[data->buff_pos];
- const wchar_t *begin = end;
-
- while( begin > buff && *begin != L'\n' )
- begin--;
-
- if( *begin == L'\n' )
- begin++;
-
- size_t len = maxi( end-begin, 1 );
- begin = end - len;
-
- reader_kill( begin - buff, len, KILL_PREPEND, last_char!=R_BACKWARD_KILL_LINE );
-
- }
- break;
-
- }
-
- case R_KILL_WHOLE_LINE:
- {
+ const wchar_t *end = &buff[data->buff_pos];
+ const wchar_t *begin = end;
+
+ while( begin > buff && *begin != L'\n' )
+ begin--;
+
+ if( *begin == L'\n' )
+ begin++;
+
+ size_t len = maxi( end-begin, 1 );
+ begin = end - len;
+
+ reader_kill( begin - buff, len, KILL_PREPEND, last_char!=R_BACKWARD_KILL_LINE );
+
+ }
+ break;
+
+ }
+
+ case R_KILL_WHOLE_LINE:
+ {
const wchar_t *buff = data->command_line.c_str();
- const wchar_t *end = &buff[data->buff_pos];
- const wchar_t *begin = end;
- size_t len;
-
- while( begin > buff && *begin != L'\n' )
- begin--;
-
- if( *begin == L'\n' )
- begin++;
-
- len = maxi( end-begin, 0 );
- begin = end - len;
-
- while( *end && *end != L'\n' )
- end++;
-
- if( begin == end && *end )
- end++;
-
- len = end-begin;
-
- if( len )
- {
- reader_kill( begin - buff, len, KILL_APPEND, last_char!=R_KILL_WHOLE_LINE );
- }
-
- break;
- }
-
+ const wchar_t *end = &buff[data->buff_pos];
+ const wchar_t *begin = end;
+ size_t len;
+
+ while( begin > buff && *begin != L'\n' )
+ begin--;
+
+ if( *begin == L'\n' )
+ begin++;
+
+ len = maxi( end-begin, 0 );
+ begin = end - len;
+
+ while( *end && *end != L'\n' )
+ end++;
+
+ if( begin == end && *end )
+ end++;
+
+ len = end-begin;
+
+ if( len )
+ {
+ reader_kill( begin - buff, len, KILL_APPEND, last_char!=R_KILL_WHOLE_LINE );
+ }
+
+ break;
+ }
+
/* yank*/
- case R_YANK:
- {
- yank_str = kill_yank();
- insert_string( yank_str );
- yank_len = wcslen( yank_str );
- break;
- }
-
+ case R_YANK:
+ {
+ yank_str = kill_yank();
+ insert_string( yank_str );
+ yank_len = wcslen( yank_str );
+ break;
+ }
+
/* rotate killring*/
- case R_YANK_POP:
- {
- if( yank_len )
- {
- for( size_t i=0; isearch_mode )
- {
- data->search_mode= NO_SEARCH;
-
- if( data->token_history_pos==-1 )
- {
- //history_reset();
+ case L'\x1b':
+ {
+ if( data->search_mode )
+ {
+ data->search_mode= NO_SEARCH;
+
+ if( data->token_history_pos==-1 )
+ {
+ //history_reset();
data->history_search.go_to_end();
- reader_set_buffer( data->search_buff.c_str(), data->search_buff.size() );
- }
- else
- {
- reader_replace_current_token( data->search_buff.c_str() );
- }
- data->search_buff.clear();
- reader_super_highlight_me_plenty( data->buff_pos );
- reader_repaint();
-
- }
-
- break;
- }
-
+ reader_set_buffer( data->search_buff.c_str(), data->search_buff.size() );
+ }
+ else
+ {
+ reader_replace_current_token( data->search_buff.c_str() );
+ }
+ data->search_buff.clear();
+ reader_super_highlight_me_plenty( data->buff_pos );
+ reader_repaint();
+
+ }
+
+ break;
+ }
+
/* delete backward*/
- case R_BACKWARD_DELETE_CHAR:
- {
- remove_backward();
- break;
- }
-
+ case R_BACKWARD_DELETE_CHAR:
+ {
+ remove_backward();
+ break;
+ }
+
/* delete forward*/
- case R_DELETE_CHAR:
- {
- /**
+ case R_DELETE_CHAR:
+ {
+ /**
Remove the current character in the character buffer and on the
screen using syntax highlighting, etc.
*/
- if( data->buff_pos < data->command_length() )
- {
- data->buff_pos++;
- remove_backward();
- }
- break;
- }
-
+ if( data->buff_pos < data->command_length() )
+ {
+ data->buff_pos++;
+ remove_backward();
+ }
+ break;
+ }
+
/*
Evaluate. If the current command is unfinished, or if
the charater is escaped using a backslash, insert a
newline
*/
- case R_EXECUTE:
- {
+ case R_EXECUTE:
+ {
/* Delete any autosuggestion */
data->autosuggestion.clear();
-
- /*
+
+ /*
Allow backslash-escaped newlines
*/
- if( is_backslashed( data->command_line.c_str(), data->buff_pos ) )
- {
- insert_char( '\n' );
- break;
- }
-
- switch( data->test_func( data->command_line.c_str() ) )
- {
-
- case 0:
- {
- /*
+ if( is_backslashed( data->command_line.c_str(), data->buff_pos ) )
+ {
+ insert_char( '\n' );
+ break;
+ }
+
+ switch( data->test_func( data->command_line.c_str() ) )
+ {
+
+ case 0:
+ {
+ /*
Finished commend, execute it
*/
- if( ! data->command_line.empty() )
- {
+ if( ! data->command_line.empty() )
+ {
if (data->history) {
data->history->add_with_file_detection(data->command_line);
}
- }
- finished=1;
- data->buff_pos=data->command_length();
- reader_repaint();
- break;
- }
-
+ }
+ finished=1;
+ data->buff_pos=data->command_length();
+ reader_repaint();
+ break;
+ }
+
/*
We are incomplete, continue editing
*/
- case PARSER_TEST_INCOMPLETE:
- {
- insert_char( '\n' );
- break;
- }
-
+ case PARSER_TEST_INCOMPLETE:
+ {
+ insert_char( '\n' );
+ break;
+ }
+
/*
Result must be some combination including an
error. The error message will already be
printed, all we need to do is repaint
*/
- default:
- {
- s_reset( &data->screen, true);
- reader_repaint();
- break;
- }
-
- }
-
- break;
- }
-
+ default:
+ {
+ s_reset( &data->screen, true);
+ reader_repaint();
+ break;
+ }
+
+ }
+
+ break;
+ }
+
/* History functions */
- case R_HISTORY_SEARCH_BACKWARD:
- case R_HISTORY_TOKEN_SEARCH_BACKWARD:
- case R_HISTORY_SEARCH_FORWARD:
- case R_HISTORY_TOKEN_SEARCH_FORWARD:
- {
- int reset = 0;
-
- if( data->search_mode == NO_SEARCH )
- {
- reset = 1;
- if( ( c == R_HISTORY_SEARCH_BACKWARD ) ||
+ case R_HISTORY_SEARCH_BACKWARD:
+ case R_HISTORY_TOKEN_SEARCH_BACKWARD:
+ case R_HISTORY_SEARCH_FORWARD:
+ case R_HISTORY_TOKEN_SEARCH_FORWARD:
+ {
+ int reset = 0;
+
+ if( data->search_mode == NO_SEARCH )
+ {
+ reset = 1;
+ if( ( c == R_HISTORY_SEARCH_BACKWARD ) ||
( c == R_HISTORY_SEARCH_FORWARD ) )
- {
- data->search_mode = LINE_SEARCH;
- }
- else
- {
- data->search_mode = TOKEN_SEARCH;
- }
-
+ {
+ data->search_mode = LINE_SEARCH;
+ }
+ else
+ {
+ data->search_mode = TOKEN_SEARCH;
+ }
+
data->search_buff.append(data->command_line);
data->history_search = history_search_t(*data->history, data->search_buff, HISTORY_SEARCH_TYPE_CONTAINS);
-
+
/* Skip the autosuggestion as history */
const wcstring &suggest = data->autosuggestion;
if (! suggest.empty()) {
data->history_search.skip_matches(wcstring_list_t(&suggest, 1 + &suggest));
}
- }
-
- switch( data->search_mode )
- {
-
- case LINE_SEARCH:
- {
- if( ( c == R_HISTORY_SEARCH_BACKWARD ) ||
+ }
+
+ switch( data->search_mode )
+ {
+
+ case LINE_SEARCH:
+ {
+ if( ( c == R_HISTORY_SEARCH_BACKWARD ) ||
( c == R_HISTORY_TOKEN_SEARCH_BACKWARD ) )
- {
- data->history_search.go_backwards();
- }
- else
- {
- if (! data->history_search.go_forwards()) {
+ {
+ data->history_search.go_backwards();
+ }
+ else
+ {
+ if (! data->history_search.go_forwards()) {
/* If you try to go forwards past the end, we just go to the end */
data->history_search.go_to_end();
}
- }
-
+ }
+
wcstring new_text;
if (data->history_search.is_at_end()) {
new_text = data->search_buff;
} else {
new_text = data->history_search.current_string();
}
- set_command_line_and_position(new_text, new_text.size());
-
- break;
- }
-
- case TOKEN_SEARCH:
- {
- if( ( c == R_HISTORY_SEARCH_BACKWARD ) ||
+ set_command_line_and_position(new_text, new_text.size());
+
+ break;
+ }
+
+ case TOKEN_SEARCH:
+ {
+ if( ( c == R_HISTORY_SEARCH_BACKWARD ) ||
( c == R_HISTORY_TOKEN_SEARCH_BACKWARD ) )
- {
- handle_token_history( SEARCH_BACKWARD, reset );
- }
- else
- {
- handle_token_history( SEARCH_FORWARD, reset );
- }
-
- break;
- }
-
- }
- break;
- }
-
-
+ {
+ handle_token_history( SEARCH_BACKWARD, reset );
+ }
+ else
+ {
+ handle_token_history( SEARCH_FORWARD, reset );
+ }
+
+ break;
+ }
+
+ }
+ break;
+ }
+
+
/* Move left*/
- case R_BACKWARD_CHAR:
- {
- if( data->buff_pos > 0 )
- {
- data->buff_pos--;
- reader_repaint();
- }
- break;
- }
-
+ case R_BACKWARD_CHAR:
+ {
+ if( data->buff_pos > 0 )
+ {
+ data->buff_pos--;
+ reader_repaint();
+ }
+ break;
+ }
+
/* Move right*/
- case R_FORWARD_CHAR:
- {
- if( data->buff_pos < data->command_length() )
- {
- data->buff_pos++;
- reader_repaint();
- } else {
+ case R_FORWARD_CHAR:
+ {
+ if( data->buff_pos < data->command_length() )
+ {
+ data->buff_pos++;
+ reader_repaint();
+ } else {
accept_autosuggestion();
}
- break;
- }
-
+ break;
+ }
+
/* kill one word left */
- case R_BACKWARD_KILL_WORD:
- {
- move_word(MOVE_DIR_LEFT, true /* erase */, last_char!=R_BACKWARD_KILL_WORD);
- break;
- }
-
+ case R_BACKWARD_KILL_WORD:
+ {
+ move_word(MOVE_DIR_LEFT, true /* erase */, last_char!=R_BACKWARD_KILL_WORD);
+ break;
+ }
+
/* kill one word right */
- case R_KILL_WORD:
- {
- move_word(MOVE_DIR_RIGHT, true /* erase */, last_char!=R_KILL_WORD);
- break;
- }
-
+ case R_KILL_WORD:
+ {
+ move_word(MOVE_DIR_RIGHT, true /* erase */, last_char!=R_KILL_WORD);
+ break;
+ }
+
/* move one word left*/
- case R_BACKWARD_WORD:
- {
- move_word(MOVE_DIR_LEFT, false /* do not erase */, false);
- break;
- }
-
+ case R_BACKWARD_WORD:
+ {
+ move_word(MOVE_DIR_LEFT, false /* do not erase */, false);
+ break;
+ }
+
/* move one word right*/
- case R_FORWARD_WORD:
- {
- move_word(MOVE_DIR_RIGHT, false /* do not erase */, false);
- break;
- }
-
- case R_BEGINNING_OF_HISTORY:
- {
+ case R_FORWARD_WORD:
+ {
+ move_word(MOVE_DIR_RIGHT, false /* do not erase */, false);
+ break;
+ }
+
+ case R_BEGINNING_OF_HISTORY:
+ {
data->history_search = history_search_t(*data->history, data->command_line, HISTORY_SEARCH_TYPE_PREFIX);
data->history_search.go_to_beginning();
if (! data->history_search.is_at_end()) {
wcstring new_text = data->history_search.current_string();
set_command_line_and_position(new_text, new_text.size());
}
-
- break;
- }
-
- case R_END_OF_HISTORY:
- {
- data->history_search.go_to_end();
- break;
- }
-
- case R_UP_LINE:
- case R_DOWN_LINE:
- {
- int line_old = parse_util_get_line_from_offset( data->command_line, data->buff_pos );
- int line_new;
-
- if( c == R_UP_LINE )
- line_new = line_old-1;
- else
- line_new = line_old+1;
-
- int line_count = parse_util_lineno( data->command_line.c_str(), data->command_length() )-1;
-
- if( line_new >= 0 && line_new <= line_count)
- {
- size_t base_pos_new;
- size_t base_pos_old;
-
- int indent_old;
- int indent_new;
- size_t line_offset_old;
- size_t total_offset_new;
-
- base_pos_new = parse_util_get_offset_from_line( data->command_line, line_new );
-
- base_pos_old = parse_util_get_offset_from_line( data->command_line, line_old );
-
- assert(base_pos_new != (size_t)(-1) && base_pos_old != (size_t)(-1));
- indent_old = data->indents.at(base_pos_old);
- indent_new = data->indents.at(base_pos_new);
-
- line_offset_old = data->buff_pos - parse_util_get_offset_from_line( data->command_line, line_old );
- total_offset_new = parse_util_get_offset( data->command_line, line_new, line_offset_old - 4*(indent_new-indent_old));
- data->buff_pos = total_offset_new;
- reader_repaint();
- }
-
- break;
- }
-
- case R_SUPPRESS_AUTOSUGGESTION:
- {
- data->suppress_autosuggestion = true;
- data->autosuggestion.clear();
- reader_repaint();
- break;
- }
-
- case R_ACCEPT_AUTOSUGGESTION:
- {
- accept_autosuggestion();
- break;
- }
-
+
+ break;
+ }
+
+ case R_END_OF_HISTORY:
+ {
+ data->history_search.go_to_end();
+ break;
+ }
+
+ case R_UP_LINE:
+ case R_DOWN_LINE:
+ {
+ int line_old = parse_util_get_line_from_offset( data->command_line, data->buff_pos );
+ int line_new;
+
+ if( c == R_UP_LINE )
+ line_new = line_old-1;
+ else
+ line_new = line_old+1;
+
+ int line_count = parse_util_lineno( data->command_line.c_str(), data->command_length() )-1;
+
+ if( line_new >= 0 && line_new <= line_count)
+ {
+ size_t base_pos_new;
+ size_t base_pos_old;
+
+ int indent_old;
+ int indent_new;
+ size_t line_offset_old;
+ size_t total_offset_new;
+
+ base_pos_new = parse_util_get_offset_from_line( data->command_line, line_new );
+
+ base_pos_old = parse_util_get_offset_from_line( data->command_line, line_old );
+
+ assert(base_pos_new != (size_t)(-1) && base_pos_old != (size_t)(-1));
+ indent_old = data->indents.at(base_pos_old);
+ indent_new = data->indents.at(base_pos_new);
+
+ line_offset_old = data->buff_pos - parse_util_get_offset_from_line( data->command_line, line_old );
+ total_offset_new = parse_util_get_offset( data->command_line, line_new, line_offset_old - 4*(indent_new-indent_old));
+ data->buff_pos = total_offset_new;
+ reader_repaint();
+ }
+
+ break;
+ }
+
+ case R_SUPPRESS_AUTOSUGGESTION:
+ {
+ data->suppress_autosuggestion = true;
+ data->autosuggestion.clear();
+ reader_repaint();
+ break;
+ }
+
+ case R_ACCEPT_AUTOSUGGESTION:
+ {
+ accept_autosuggestion();
+ break;
+ }
+
/* Other, if a normal character, we add it to the command */
- default:
- {
-
- if( (!wchar_private(c)) && (( (c>31) || (c==L'\n'))&& (c != 127)) )
- {
+ default:
+ {
+
+ if( (!wchar_private(c)) && (( (c>31) || (c==L'\n'))&& (c != 127)) )
+ {
/* Regular character */
- insert_char( c );
- }
- else
- {
- /*
+ insert_char( c );
+ }
+ else
+ {
+ /*
Low priority debug message. These can happen if
the user presses an unefined control
sequnece. No reason to report.
*/
- debug( 2, _( L"Unknown keybinding %d" ), c );
- }
- break;
- }
-
- }
-
- if( (c != R_HISTORY_SEARCH_BACKWARD) &&
+ debug( 2, _( L"Unknown keybinding %d" ), c );
+ }
+ break;
+ }
+
+ }
+
+ if( (c != R_HISTORY_SEARCH_BACKWARD) &&
(c != R_HISTORY_SEARCH_FORWARD) &&
(c != R_HISTORY_TOKEN_SEARCH_BACKWARD) &&
(c != R_HISTORY_TOKEN_SEARCH_FORWARD) &&
(c != R_NULL) )
- {
- data->search_mode = NO_SEARCH;
- data->search_buff.clear();
- data->history_search.go_to_end();
- data->token_history_pos=-1;
- }
-
- last_char = c;
- }
-
- writestr( L"\n" );
+ {
+ data->search_mode = NO_SEARCH;
+ data->search_buff.clear();
+ data->history_search.go_to_end();
+ data->token_history_pos=-1;
+ }
+
+ last_char = c;
+ }
+
+ writestr( L"\n" );
/*
if( comp )
halloc_free( comp );
*/
- if( !reader_exit_forced() )
- {
- if( tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */
- {
- wperror(L"tcsetattr");
- }
-
- set_color( rgb_color_t::reset(), rgb_color_t::reset() );
- }
-
- return finished ? data->command_line.c_str() : 0;
+ if( !reader_exit_forced() )
+ {
+ if( tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */
+ {
+ wperror(L"tcsetattr");
+ }
+
+ set_color( rgb_color_t::reset(), rgb_color_t::reset() );
+ }
+
+ return finished ? data->command_line.c_str() : 0;
}
int reader_search_mode()
{
- if( !data )
- {
- return -1;
- }
-
- return !!data->search_mode;
+ if( !data )
+ {
+ return -1;
+ }
+
+ return !!data->search_mode;
}
@@ -3310,123 +3319,123 @@ int reader_search_mode()
static int read_ni( int fd, const io_chain_t &io )
{
parser_t &parser = parser_t::principal_parser();
- FILE *in_stream;
- wchar_t *buff=0;
- std::vector acc;
+ FILE *in_stream;
+ wchar_t *buff=0;
+ std::vector acc;
- int des = fd == 0 ? dup(0) : fd;
- int res=0;
+ int des = fd == 0 ? dup(0) : fd;
+ int res=0;
- if (des == -1)
- {
- wperror( L"dup" );
- return 1;
- }
+ if (des == -1)
+ {
+ wperror( L"dup" );
+ return 1;
+ }
- in_stream = fdopen( des, "r" );
- if( in_stream != 0 )
- {
- wchar_t *str;
- size_t acc_used;
+ in_stream = fdopen( des, "r" );
+ if( in_stream != 0 )
+ {
+ wchar_t *str;
+ size_t acc_used;
- while(!feof( in_stream ))
- {
- char buff[4096];
- size_t c = fread(buff, 1, 4096, in_stream);
+ while(!feof( in_stream ))
+ {
+ char buff[4096];
+ size_t c = fread(buff, 1, 4096, in_stream);
+
+ if( ferror( in_stream ) && ( errno != EINTR ) )
+ {
+ debug( 1,
+ _( L"Error while reading from file descriptor" ) );
+
+ /*
+ Reset buffer on error. We won't evaluate incomplete files.
+ */
+ acc.clear();
+ break;
+
+ }
- if( ferror( in_stream ) && ( errno != EINTR ) )
- {
- debug( 1,
- _( L"Error while reading from file descriptor" ) );
-
- /*
- Reset buffer on error. We won't evaluate incomplete files.
- */
- acc.clear();
- break;
-
- }
-
- acc.insert(acc.end(), buff, buff + c);
- }
+ acc.insert(acc.end(), buff, buff + c);
+ }
acc.push_back(0);
- acc_used = acc.size();
- str = str2wcs(&acc.at(0));
+ acc_used = acc.size();
+ str = str2wcs(&acc.at(0));
acc.clear();
- if( fclose( in_stream ))
- {
- debug( 1,
- _( L"Error while closing input stream" ) );
- wperror( L"fclose" );
- res = 1;
- }
+ if( fclose( in_stream ))
+ {
+ debug( 1,
+ _( L"Error while closing input stream" ) );
+ wperror( L"fclose" );
+ res = 1;
+ }
- if( str )
- {
- wcstring sb;
- if( ! parser.test( str, 0, &sb, L"fish" ) )
- {
- parser.eval( str, io, TOP );
- }
- else
- {
- fwprintf( stderr, L"%ls", sb.c_str() );
- res = 1;
- }
- free( str );
- }
- else
- {
- if( acc_used > 1 )
- {
- debug( 1,
- _( L"Could not convert input. Read %d bytes." ),
- acc_used-1 );
- }
- else
- {
- debug( 1,
- _( L"Could not read input stream" ) );
- }
- res=1;
- }
+ if( str )
+ {
+ wcstring sb;
+ if( ! parser.test( str, 0, &sb, L"fish" ) )
+ {
+ parser.eval( str, io, TOP );
+ }
+ else
+ {
+ fwprintf( stderr, L"%ls", sb.c_str() );
+ res = 1;
+ }
+ free( str );
+ }
+ else
+ {
+ if( acc_used > 1 )
+ {
+ debug( 1,
+ _( L"Could not convert input. Read %d bytes." ),
+ acc_used-1 );
+ }
+ else
+ {
+ debug( 1,
+ _( L"Could not read input stream" ) );
+ }
+ res=1;
+ }
- }
- else
- {
- debug( 1,
- _( L"Error while opening input stream" ) );
- wperror( L"fdopen" );
- free( buff );
- res=1;
- }
- return res;
+ }
+ else
+ {
+ debug( 1,
+ _( L"Error while opening input stream" ) );
+ wperror( L"fdopen" );
+ free( buff );
+ res=1;
+ }
+ return res;
}
int reader_read( int fd, const io_chain_t &io )
{
- int res;
+ int res;
- /*
- If reader_read is called recursively through the '.' builtin, we
- need to preserve is_interactive. This, and signal handler setup
- is handled by proc_push_interactive/proc_pop_interactive.
- */
+ /*
+ If reader_read is called recursively through the '.' builtin, we
+ need to preserve is_interactive. This, and signal handler setup
+ is handled by proc_push_interactive/proc_pop_interactive.
+ */
- int inter = ((fd == STDIN_FILENO) && isatty(STDIN_FILENO));
- proc_push_interactive( inter );
+ int inter = ((fd == STDIN_FILENO) && isatty(STDIN_FILENO));
+ proc_push_interactive( inter );
+
+ res= get_is_interactive() ? read_i():read_ni( fd, io );
- res= get_is_interactive() ? read_i():read_ni( fd, io );
-
- /*
- If the exit command was called in a script, only exit the
- script, not the program.
- */
- if( data )
- data->end_loop = 0;
- end_loop = 0;
-
- proc_pop_interactive();
- return res;
+ /*
+ If the exit command was called in a script, only exit the
+ script, not the program.
+ */
+ if( data )
+ data->end_loop = 0;
+ end_loop = 0;
+
+ proc_pop_interactive();
+ return res;
}
diff --git a/reader.h b/reader.h
index db8dfcb4d..8a7ed5d40 100644
--- a/reader.h
+++ b/reader.h
@@ -1,9 +1,9 @@
-/** \file reader.h
+/** \file reader.h
Prototypes for functions for reading data from stdin and passing
- to the parser. If stdin is a keyboard, it supplies a killring,
- history, syntax highlighting, tab-completion and various other
- features.
+ to the parser. If stdin is a keyboard, it supplies a killring,
+ history, syntax highlighting, tab-completion and various other
+ features.
*/
#ifndef FISH_READER_H
@@ -53,7 +53,7 @@ const wchar_t *reader_current_filename();
/**
Push a new filename on the stack of read files
-
+
\param fn The fileanme to push
*/
void reader_push_current_filename( const wchar_t *fn );
@@ -125,7 +125,7 @@ int reader_interrupted();
const wchar_t *reader_readline();
/**
- Push a new reader environment.
+ Push a new reader environment.
*/
void reader_push( const wchar_t *name );
@@ -135,7 +135,7 @@ void reader_push( const wchar_t *name );
void reader_pop();
/**
- Specify function to use for finding possible tab completions. The function must take these arguments:
+ Specify function to use for finding possible tab completions. The function must take these arguments:
- The command to be completed as a null terminated array of wchar_t
- An array_list_t in which completions will be inserted.
@@ -151,7 +151,7 @@ typedef void (*highlight_function_t)( const wcstring &, std::vector &, size
/**
Specify function for syntax highlighting. The function must take these arguments:
-
+
- The command to be highlighted as a null terminated array of wchar_t
- The color code of each character as an array of ints
- The cursor position
@@ -177,8 +177,12 @@ void reader_set_left_prompt( const wcstring &prompt );
*/
void reader_set_right_prompt( const wcstring &prompt );
+
+/** Sets whether autosuggesting is allowed. */
+void reader_set_allow_autosuggesting(bool flag);
+
/**
- Returns true if the shell is exiting, 0 otherwise.
+ Returns true if the shell is exiting, 0 otherwise.
*/
int exit_status();
diff --git a/share/functions/__fish_config_interactive.fish b/share/functions/__fish_config_interactive.fish
index 8409fc5f1..b2c56aee7 100644
--- a/share/functions/__fish_config_interactive.fish
+++ b/share/functions/__fish_config_interactive.fish
@@ -120,7 +120,7 @@ function __fish_config_interactive -d "Initializations that should be performed
# Pager colors
set_default fish_pager_color_prefix cyan
set_default fish_pager_color_completion normal
- set_default fish_pager_color_description normal
+ set_default fish_pager_color_description 555 yellow
set_default fish_pager_color_progress cyan
#
diff --git a/signal.cpp b/signal.cpp
index d25f2b063..98883bf4e 100644
--- a/signal.cpp
+++ b/signal.cpp
@@ -36,18 +36,18 @@ The library for various signal related issues
*/
struct lookup_entry
{
- /**
- Signal id
- */
- int signal;
- /**
- Signal name
- */
- const wchar_t *name;
- /**
- Signal description
- */
- const wchar_t *desc;
+ /**
+ Signal id
+ */
+ int signal;
+ /**
+ Signal name
+ */
+ const wchar_t *name;
+ /**
+ Signal description
+ */
+ const wchar_t *desc;
};
/**
@@ -63,363 +63,363 @@ static int block_count=0;
static const struct lookup_entry lookup[] =
{
#ifdef SIGHUP
- {
- SIGHUP,
- L"SIGHUP",
- N_( L"Terminal hung up" )
- }
- ,
+ {
+ SIGHUP,
+ L"SIGHUP",
+ N_( L"Terminal hung up" )
+ }
+ ,
#endif
#ifdef SIGINT
- {
- SIGINT,
- L"SIGINT",
- N_( L"Quit request from job control (^C)" )
- }
- ,
+ {
+ SIGINT,
+ L"SIGINT",
+ N_( L"Quit request from job control (^C)" )
+ }
+ ,
#endif
#ifdef SIGQUIT
- {
- SIGQUIT,
- L"SIGQUIT",
- N_( L"Quit request from job control with core dump (^\\)" )
- }
- ,
+ {
+ SIGQUIT,
+ L"SIGQUIT",
+ N_( L"Quit request from job control with core dump (^\\)" )
+ }
+ ,
#endif
#ifdef SIGILL
- {
- SIGILL,
- L"SIGILL",
- N_( L"Illegal instruction" )
- }
- ,
+ {
+ SIGILL,
+ L"SIGILL",
+ N_( L"Illegal instruction" )
+ }
+ ,
#endif
#ifdef SIGTRAP
- {
- SIGTRAP,
- L"SIGTRAP",
- N_( L"Trace or breakpoint trap" )
- }
- ,
+ {
+ SIGTRAP,
+ L"SIGTRAP",
+ N_( L"Trace or breakpoint trap" )
+ }
+ ,
#endif
#ifdef SIGABRT
- {
- SIGABRT,
- L"SIGABRT",
- N_( L"Abort" )
- }
- ,
+ {
+ SIGABRT,
+ L"SIGABRT",
+ N_( L"Abort" )
+ }
+ ,
#endif
#ifdef SIGBUS
- {
- SIGBUS,
- L"SIGBUS",
- N_( L"Misaligned address error" )
- }
- ,
+ {
+ SIGBUS,
+ L"SIGBUS",
+ N_( L"Misaligned address error" )
+ }
+ ,
#endif
#ifdef SIGFPE
- {
- SIGFPE,
- L"SIGFPE",
- N_( L"Floating point exception" )
- }
- ,
+ {
+ SIGFPE,
+ L"SIGFPE",
+ N_( L"Floating point exception" )
+ }
+ ,
#endif
#ifdef SIGKILL
- {
- SIGKILL,
- L"SIGKILL",
- N_( L"Forced quit" )
- }
- ,
+ {
+ SIGKILL,
+ L"SIGKILL",
+ N_( L"Forced quit" )
+ }
+ ,
#endif
#ifdef SIGUSR1
- {
- SIGUSR1,
- L"SIGUSR1",
- N_( L"User defined signal 1" )
- }
- ,
+ {
+ SIGUSR1,
+ L"SIGUSR1",
+ N_( L"User defined signal 1" )
+ }
+ ,
#endif
#ifdef SIGUSR2
- {
- SIGUSR2, L"SIGUSR2",
- N_( L"User defined signal 2" )
- }
- ,
+ {
+ SIGUSR2, L"SIGUSR2",
+ N_( L"User defined signal 2" )
+ }
+ ,
#endif
#ifdef SIGSEGV
- {
- SIGSEGV,
- L"SIGSEGV",
- N_( L"Address boundary error" )
- }
- ,
+ {
+ SIGSEGV,
+ L"SIGSEGV",
+ N_( L"Address boundary error" )
+ }
+ ,
#endif
#ifdef SIGPIPE
- {
- SIGPIPE,
- L"SIGPIPE",
- N_( L"Broken pipe" )
- }
- ,
+ {
+ SIGPIPE,
+ L"SIGPIPE",
+ N_( L"Broken pipe" )
+ }
+ ,
#endif
#ifdef SIGALRM
- {
- SIGALRM,
- L"SIGALRM",
- N_( L"Timer expired" )
- }
- ,
+ {
+ SIGALRM,
+ L"SIGALRM",
+ N_( L"Timer expired" )
+ }
+ ,
#endif
#ifdef SIGTERM
- {
- SIGTERM,
- L"SIGTERM",
- N_( L"Polite quit request" )
- }
- ,
+ {
+ SIGTERM,
+ L"SIGTERM",
+ N_( L"Polite quit request" )
+ }
+ ,
#endif
#ifdef SIGCHLD
- {
- SIGCHLD,
- L"SIGCHLD",
- N_( L"Child process status changed" )
- }
- ,
+ {
+ SIGCHLD,
+ L"SIGCHLD",
+ N_( L"Child process status changed" )
+ }
+ ,
#endif
#ifdef SIGCONT
- {
- SIGCONT,
- L"SIGCONT",
- N_( L"Continue previously stopped process" )
- }
- ,
+ {
+ SIGCONT,
+ L"SIGCONT",
+ N_( L"Continue previously stopped process" )
+ }
+ ,
#endif
#ifdef SIGSTOP
- {
- SIGSTOP,
- L"SIGSTOP",
- N_( L"Forced stop" )
- }
- ,
+ {
+ SIGSTOP,
+ L"SIGSTOP",
+ N_( L"Forced stop" )
+ }
+ ,
#endif
#ifdef SIGTSTP
- {
- SIGTSTP,
- L"SIGTSTP",
- N_( L"Stop request from job control (^Z)" )
- }
- ,
+ {
+ SIGTSTP,
+ L"SIGTSTP",
+ N_( L"Stop request from job control (^Z)" )
+ }
+ ,
#endif
#ifdef SIGTTIN
- {
- SIGTTIN,
- L"SIGTTIN",
- N_( L"Stop from terminal input" )
- }
- ,
+ {
+ SIGTTIN,
+ L"SIGTTIN",
+ N_( L"Stop from terminal input" )
+ }
+ ,
#endif
#ifdef SIGTTOU
- {
- SIGTTOU,
- L"SIGTTOU",
- N_( L"Stop from terminal output" )
- }
- ,
+ {
+ SIGTTOU,
+ L"SIGTTOU",
+ N_( L"Stop from terminal output" )
+ }
+ ,
#endif
#ifdef SIGURG
- {
- SIGURG,
- L"SIGURG",
- N_( L"Urgent socket condition" )
- }
- ,
+ {
+ SIGURG,
+ L"SIGURG",
+ N_( L"Urgent socket condition" )
+ }
+ ,
#endif
#ifdef SIGXCPU
- {
- SIGXCPU,
- L"SIGXCPU",
- N_( L"CPU time limit exceeded" )
- }
- ,
+ {
+ SIGXCPU,
+ L"SIGXCPU",
+ N_( L"CPU time limit exceeded" )
+ }
+ ,
#endif
#ifdef SIGXFSZ
- {
- SIGXFSZ,
- L"SIGXFSZ",
- N_( L"File size limit exceeded" )
- }
- ,
+ {
+ SIGXFSZ,
+ L"SIGXFSZ",
+ N_( L"File size limit exceeded" )
+ }
+ ,
#endif
#ifdef SIGVTALRM
- {
- SIGVTALRM,
- L"SIGVTALRM",
- N_( L"Virtual timer expired" )
- }
- ,
+ {
+ SIGVTALRM,
+ L"SIGVTALRM",
+ N_( L"Virtual timer expired" )
+ }
+ ,
#endif
#ifdef SIGPROF
- {
- SIGPROF,
- L"SIGPROF",
- N_( L"Profiling timer expired" )
- }
- ,
+ {
+ SIGPROF,
+ L"SIGPROF",
+ N_( L"Profiling timer expired" )
+ }
+ ,
#endif
#ifdef SIGWINCH
- {
- SIGWINCH,
- L"SIGWINCH",
- N_( L"Window size change" )
- }
- ,
+ {
+ SIGWINCH,
+ L"SIGWINCH",
+ N_( L"Window size change" )
+ }
+ ,
#endif
#ifdef SIGWIND
- {
- SIGWIND,
- L"SIGWIND",
- N_( L"Window size change" )
- }
- ,
+ {
+ SIGWIND,
+ L"SIGWIND",
+ N_( L"Window size change" )
+ }
+ ,
#endif
#ifdef SIGIO
- {
- SIGIO,
- L"SIGIO",
- N_( L"I/O on asynchronous file descriptor is possible" )
- }
- ,
+ {
+ SIGIO,
+ L"SIGIO",
+ N_( L"I/O on asynchronous file descriptor is possible" )
+ }
+ ,
#endif
#ifdef SIGPWR
- {
- SIGPWR,
- L"SIGPWR",
- N_( L"Power failure" )
- }
- ,
+ {
+ SIGPWR,
+ L"SIGPWR",
+ N_( L"Power failure" )
+ }
+ ,
#endif
#ifdef SIGSYS
- {
- SIGSYS,
- L"SIGSYS",
- N_( L"Bad system call" )
- }
- ,
+ {
+ SIGSYS,
+ L"SIGSYS",
+ N_( L"Bad system call" )
+ }
+ ,
#endif
#ifdef SIGINFO
- {
- SIGINFO,
- L"SIGINFO",
- N_( L"Information request" )
- }
- ,
+ {
+ SIGINFO,
+ L"SIGINFO",
+ N_( L"Information request" )
+ }
+ ,
#endif
#ifdef SIGSTKFLT
- {
- SIGSTKFLT,
- L"SISTKFLT",
- N_( L"Stack fault" )
- }
- ,
+ {
+ SIGSTKFLT,
+ L"SISTKFLT",
+ N_( L"Stack fault" )
+ }
+ ,
#endif
#ifdef SIGEMT
- {
- SIGEMT,
- L"SIGEMT",
- N_( L"Emulator trap" )
- }
- ,
+ {
+ SIGEMT,
+ L"SIGEMT",
+ N_( L"Emulator trap" )
+ }
+ ,
#endif
#ifdef SIGIOT
- {
- SIGIOT,
- L"SIGIOT",
- N_( L"Abort (Alias for SIGABRT)" )
- }
- ,
+ {
+ SIGIOT,
+ L"SIGIOT",
+ N_( L"Abort (Alias for SIGABRT)" )
+ }
+ ,
#endif
#ifdef SIGUNUSED
- {
- SIGUNUSED,
- L"SIGUNUSED",
- N_( L"Unused signal" )
- }
- ,
+ {
+ SIGUNUSED,
+ L"SIGUNUSED",
+ N_( L"Unused signal" )
+ }
+ ,
#endif
- {
- 0,
- 0,
- 0
- }
+ {
+ 0,
+ 0,
+ 0
+ }
}
- ;
+ ;
/**
- Test if \c name is a string describing the signal named \c canonical.
+ Test if \c name is a string describing the signal named \c canonical.
*/
-static int match_signal_name( const wchar_t *canonical,
- const wchar_t *name )
+static int match_signal_name( const wchar_t *canonical,
+ const wchar_t *name )
{
- if( wcsncasecmp( name, L"sig", 3 )==0)
- name +=3;
+ if( wcsncasecmp( name, L"sig", 3 )==0)
+ name +=3;
- return wcscasecmp( canonical+3,name ) == 0;
+ return wcscasecmp( canonical+3,name ) == 0;
}
int wcs2sig( const wchar_t *str )
{
- int i;
- wchar_t *end=0;
+ int i;
+ wchar_t *end=0;
+
+ for( i=0; lookup[i].desc ; i++ )
+ {
+ if( match_signal_name( lookup[i].name, str) )
+ {
+ return lookup[i].signal;
+ }
+ }
+ errno=0;
+ int res = fish_wcstoi( str, &end, 10 );
+ if( !errno && res>=0 && !*end )
+ return res;
- for( i=0; lookup[i].desc ; i++ )
- {
- if( match_signal_name( lookup[i].name, str) )
- {
- return lookup[i].signal;
- }
- }
- errno=0;
- int res = fish_wcstoi( str, &end, 10 );
- if( !errno && res>=0 && !*end )
- return res;
-
- return -1;
+ return -1;
}
const wchar_t *sig2wcs( int sig )
{
- int i;
+ int i;
- for( i=0; lookup[i].desc ; i++ )
- {
- if( lookup[i].signal == sig )
- {
- return lookup[i].name;
- }
- }
+ for( i=0; lookup[i].desc ; i++ )
+ {
+ if( lookup[i].signal == sig )
+ {
+ return lookup[i].name;
+ }
+ }
- return _(L"Unknown");
+ return _(L"Unknown");
}
const wchar_t *signal_get_desc( int sig )
{
- int i;
+ int i;
- for( i=0; lookup[i].desc ; i++ )
- {
- if( lookup[i].signal == sig )
- {
- return _(lookup[i].desc);
- }
- }
+ for( i=0; lookup[i].desc ; i++ )
+ {
+ if( lookup[i].signal == sig )
+ {
+ return _(lookup[i].desc);
+ }
+ }
- return _(L"Unknown");
+ return _(L"Unknown");
}
/**
@@ -429,8 +429,8 @@ static void default_handler(int signal, siginfo_t *info, void *context)
{
if (event_is_signal_observed(signal))
{
- event_fire_signal(signal);
- }
+ event_fire_signal(signal);
+ }
}
/**
@@ -438,8 +438,8 @@ static void default_handler(int signal, siginfo_t *info, void *context)
*/
static void handle_winch( int sig, siginfo_t *info, void *context )
{
- common_handle_winch( sig );
- default_handler( sig, 0, 0 );
+ common_handle_winch( sig );
+ default_handler( sig, 0, 0 );
}
/**
@@ -448,14 +448,22 @@ static void handle_winch( int sig, siginfo_t *info, void *context )
*/
static void handle_hup( int sig, siginfo_t *info, void *context )
{
- if (event_is_signal_observed(SIGHUP))
- {
- default_handler(sig, 0, 0);
- }
- else
- {
- reader_exit(1, 1);
- }
+ if (event_is_signal_observed(SIGHUP))
+ {
+ default_handler(sig, 0, 0);
+ }
+ else
+ {
+ reader_exit(1, 1);
+ }
+}
+
+/** Handle sigterm. The only thing we do is restore the front process ID, then die. */
+static void handle_term( int sig, siginfo_t *info, void *context )
+{
+ restore_term_foreground_process_group();
+ signal(SIGTERM, SIG_DFL);
+ raise(SIGTERM);
}
/**
@@ -464,8 +472,8 @@ static void handle_hup( int sig, siginfo_t *info, void *context )
*/
static void handle_int( int sig, siginfo_t *info, void *context )
{
- reader_handle_int( sig );
- default_handler( sig, info, context);
+ reader_handle_int( sig );
+ default_handler( sig, info, context);
}
/**
@@ -473,23 +481,23 @@ static void handle_int( int sig, siginfo_t *info, void *context )
*/
static void handle_chld( int sig, siginfo_t *info, void *context )
{
- job_handle_signal( sig, info, context );
- default_handler( sig, info, context);
+ job_handle_signal( sig, info, context );
+ default_handler( sig, info, context);
}
void signal_reset_handlers()
{
- int i;
-
- struct sigaction act;
- sigemptyset( & act.sa_mask );
- act.sa_flags=0;
- act.sa_handler=SIG_DFL;
-
- for( i=0; lookup[i].desc ; i++ )
- {
- sigaction( lookup[i].signal, &act, 0);
- }
+ int i;
+
+ struct sigaction act;
+ sigemptyset( & act.sa_mask );
+ act.sa_flags=0;
+ act.sa_handler=SIG_DFL;
+
+ for( i=0; lookup[i].desc ; i++ )
+ {
+ sigaction( lookup[i].signal, &act, 0);
+ }
}
@@ -498,187 +506,196 @@ void signal_reset_handlers()
*/
void signal_set_handlers()
{
- struct sigaction act;
+ struct sigaction act;
- if( get_is_interactive() == -1 )
- return;
+ if( get_is_interactive() == -1 )
+ return;
+
+ sigemptyset( & act.sa_mask );
+ act.sa_flags=SA_SIGINFO;
+ act.sa_sigaction = &default_handler;
+
+ /*
+ First reset everything to a use default_handler, a function
+ whose sole action is to fire of an event
+ */
+ sigaction( SIGINT, &act, 0);
+ sigaction( SIGQUIT, &act, 0);
+ sigaction( SIGTSTP, &act, 0);
+ sigaction( SIGTTIN, &act, 0);
+ sigaction( SIGTTOU, &act, 0);
+ sigaction( SIGCHLD, &act, 0);
+
+ /*
+ Ignore sigpipe, it is generated if fishd dies, but we can
+ recover.
+ */
+ sigaction( SIGPIPE, &act, 0);
- sigemptyset( & act.sa_mask );
- act.sa_flags=SA_SIGINFO;
- act.sa_sigaction = &default_handler;
+ if( get_is_interactive() )
+ {
+ /*
+ Interactive mode. Ignore interactive signals. We are a
+ shell, we know whats best for the user. ;-)
+ */
+
+ act.sa_handler=SIG_IGN;
+
+ sigaction( SIGINT, &act, 0);
+ sigaction( SIGQUIT, &act, 0);
+ sigaction( SIGTSTP, &act, 0);
+ sigaction( SIGTTIN, &act, 0);
+ sigaction( SIGTTOU, &act, 0);
- /*
- First reset everything to a use default_handler, a function
- whose sole action is to fire of an event
- */
- sigaction( SIGINT, &act, 0);
- sigaction( SIGQUIT, &act, 0);
- sigaction( SIGTSTP, &act, 0);
- sigaction( SIGTTIN, &act, 0);
- sigaction( SIGTTOU, &act, 0);
- sigaction( SIGCHLD, &act, 0);
-
- /*
- Ignore sigpipe, it is generated if fishd dies, but we can
- recover.
- */
- sigaction( SIGPIPE, &act, 0);
-
- if( get_is_interactive() )
- {
- /*
- Interactive mode. Ignore interactive signals. We are a
- shell, we know whats best for the user. ;-)
- */
-
- act.sa_handler=SIG_IGN;
-
- sigaction( SIGINT, &act, 0);
- sigaction( SIGQUIT, &act, 0);
- sigaction( SIGTSTP, &act, 0);
- sigaction( SIGTTIN, &act, 0);
- sigaction( SIGTTOU, &act, 0);
-
- act.sa_sigaction = &handle_int;
- act.sa_flags = SA_SIGINFO;
- if( sigaction( SIGINT, &act, 0) )
- {
- wperror( L"sigaction" );
- FATAL_EXIT();
- }
-
- act.sa_sigaction = &handle_chld;
- act.sa_flags = SA_SIGINFO;
- if( sigaction( SIGCHLD, &act, 0) )
- {
- wperror( L"sigaction" );
- FATAL_EXIT();
- }
+ act.sa_sigaction = &handle_int;
+ act.sa_flags = SA_SIGINFO;
+ if( sigaction( SIGINT, &act, 0) )
+ {
+ wperror( L"sigaction" );
+ FATAL_EXIT();
+ }
+ act.sa_sigaction = &handle_chld;
+ act.sa_flags = SA_SIGINFO;
+ if( sigaction( SIGCHLD, &act, 0) )
+ {
+ wperror( L"sigaction" );
+ FATAL_EXIT();
+ }
+
#ifdef SIGWINCH
- act.sa_flags = SA_SIGINFO;
- act.sa_sigaction= &handle_winch;
- if( sigaction( SIGWINCH, &act, 0 ) )
- {
- wperror( L"sigaction" );
- FATAL_EXIT();
- }
+ act.sa_flags = SA_SIGINFO;
+ act.sa_sigaction= &handle_winch;
+ if( sigaction( SIGWINCH, &act, 0 ) )
+ {
+ wperror( L"sigaction" );
+ FATAL_EXIT();
+ }
#endif
- act.sa_flags = SA_SIGINFO;
- act.sa_sigaction= &handle_hup;
- if( sigaction( SIGHUP, &act, 0 ) )
- {
- wperror( L"sigaction" );
- FATAL_EXIT();
- }
+ act.sa_flags = SA_SIGINFO;
+ act.sa_sigaction= &handle_hup;
+ if( sigaction( SIGHUP, &act, 0 ) )
+ {
+ wperror( L"sigaction" );
+ FATAL_EXIT();
+ }
+
+ // SIGTERM restores the terminal controlling process before dying
+ act.sa_flags = SA_SIGINFO;
+ act.sa_sigaction= &handle_term;
+ if( sigaction( SIGTERM, &act, 0 ) )
+ {
+ wperror( L"sigaction" );
+ FATAL_EXIT();
+ }
- }
- else
- {
- /*
- Non-interactive. Ignore interrupt, check exit status of
- processes to determine result instead.
- */
- act.sa_handler=SIG_IGN;
+ }
+ else
+ {
+ /*
+ Non-interactive. Ignore interrupt, check exit status of
+ processes to determine result instead.
+ */
+ act.sa_handler=SIG_IGN;
- sigaction( SIGINT, &act, 0);
- sigaction( SIGQUIT, &act, 0);
+ sigaction( SIGINT, &act, 0);
+ sigaction( SIGQUIT, &act, 0);
- act.sa_handler=SIG_DFL;
-
- act.sa_sigaction = &handle_chld;
- act.sa_flags = SA_SIGINFO;
- if( sigaction( SIGCHLD, &act, 0) )
- {
- wperror( L"sigaction" );
- exit_without_destructors(1);
- }
- }
+ act.sa_handler=SIG_DFL;
+ act.sa_sigaction = &handle_chld;
+ act.sa_flags = SA_SIGINFO;
+ if( sigaction( SIGCHLD, &act, 0) )
+ {
+ wperror( L"sigaction" );
+ exit_without_destructors(1);
+ }
+ }
+
}
void signal_handle( int sig, int do_handle )
{
- struct sigaction act;
-
- /*
- These should always be handled
- */
- if( (sig == SIGINT) ||
- (sig == SIGQUIT) ||
- (sig == SIGTSTP) ||
- (sig == SIGTTIN) ||
- (sig == SIGTTOU) ||
- (sig == SIGCHLD) )
- return;
-
- sigemptyset( &act.sa_mask );
- if( do_handle )
- {
- act.sa_flags = SA_SIGINFO;
- act.sa_sigaction = &default_handler;
- }
- else
- {
- act.sa_flags = 0;
- act.sa_handler = SIG_DFL;
- }
-
- sigaction( sig, &act, 0);
+ struct sigaction act;
+
+ /*
+ These should always be handled
+ */
+ if( (sig == SIGINT) ||
+ (sig == SIGQUIT) ||
+ (sig == SIGTSTP) ||
+ (sig == SIGTTIN) ||
+ (sig == SIGTTOU) ||
+ (sig == SIGCHLD) )
+ return;
+
+ sigemptyset( &act.sa_mask );
+ if( do_handle )
+ {
+ act.sa_flags = SA_SIGINFO;
+ act.sa_sigaction = &default_handler;
+ }
+ else
+ {
+ act.sa_flags = 0;
+ act.sa_handler = SIG_DFL;
+ }
+
+ sigaction( sig, &act, 0);
}
void get_signals_with_handlers(sigset_t *set)
{
sigemptyset(set);
- for( int i=0; lookup[i].desc ; i++ )
- {
+ for( int i=0; lookup[i].desc ; i++ )
+ {
struct sigaction act = {};
- sigaction(lookup[i].signal, NULL, &act);
+ sigaction(lookup[i].signal, NULL, &act);
if (act.sa_handler != SIG_DFL)
sigaddset(set, lookup[i].signal);
- }
+ }
}
void signal_block()
{
ASSERT_IS_MAIN_THREAD();
- sigset_t chldset;
-
- if( !block_count )
- {
- sigfillset( &chldset );
- VOMIT_ON_FAILURE(pthread_sigmask(SIG_BLOCK, &chldset, NULL));
- }
-
- block_count++;
-// debug( 0, L"signal block level increased to %d", block_count );
+ sigset_t chldset;
+
+ if( !block_count )
+ {
+ sigfillset( &chldset );
+ VOMIT_ON_FAILURE(pthread_sigmask(SIG_BLOCK, &chldset, NULL));
+ }
+
+ block_count++;
+// debug( 0, L"signal block level increased to %d", block_count );
}
void signal_unblock()
{
ASSERT_IS_MAIN_THREAD();
- sigset_t chldset;
+ sigset_t chldset;
- block_count--;
+ block_count--;
- if( block_count < 0 )
- {
- debug( 0, _( L"Signal block mismatch" ) );
- bugreport();
- FATAL_EXIT();
- }
-
- if( !block_count )
- {
- sigfillset( &chldset );
- VOMIT_ON_FAILURE(pthread_sigmask(SIG_UNBLOCK, &chldset, 0));
- }
-// debug( 0, L"signal block level decreased to %d", block_count );
+ if( block_count < 0 )
+ {
+ debug( 0, _( L"Signal block mismatch" ) );
+ bugreport();
+ FATAL_EXIT();
+ }
+
+ if( !block_count )
+ {
+ sigfillset( &chldset );
+ VOMIT_ON_FAILURE(pthread_sigmask(SIG_UNBLOCK, &chldset, 0));
+ }
+// debug( 0, L"signal block level decreased to %d", block_count );
}
int signal_is_blocked()
{
- return !!block_count;
+ return !!block_count;
}