mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-12 21:18:53 +00:00
Use csh-style error rules with wildcards, i.e. if no matches are found, the command is not executed
darcs-hash:20051203164356-ac50b-1b1818db2698eab9ae765a5af1e259bce3ab37e7.gz
This commit is contained in:
parent
e2ebc0e443
commit
9b4c34aa4c
9 changed files with 218 additions and 75 deletions
19
complete.c
19
complete.c
|
@ -1213,10 +1213,12 @@ static void complete_cmd( const wchar_t *cmd,
|
|||
array_list_t tmp;
|
||||
al_init( &tmp );
|
||||
|
||||
expand_string( wcsdup(cmd),
|
||||
if( expand_string( wcsdup(cmd),
|
||||
comp,
|
||||
ACCEPT_INCOMPLETE | EXECUTABLES_ONLY );
|
||||
ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
||||
{
|
||||
complete_cmd_desc( cmd, comp );
|
||||
}
|
||||
al_destroy( &tmp );
|
||||
}
|
||||
else
|
||||
|
@ -1237,15 +1239,16 @@ static void complete_cmd( const wchar_t *cmd,
|
|||
|
||||
al_init( &tmp );
|
||||
|
||||
expand_string( nxt_completion,
|
||||
if( expand_string( nxt_completion,
|
||||
&tmp,
|
||||
ACCEPT_INCOMPLETE |
|
||||
EXECUTABLES_ONLY );
|
||||
|
||||
EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
||||
{
|
||||
for( i=0; i<al_get_count(&tmp); i++ )
|
||||
{
|
||||
al_push( comp, al_get( &tmp, i ) );
|
||||
}
|
||||
}
|
||||
|
||||
al_destroy( &tmp );
|
||||
|
||||
|
@ -1290,9 +1293,10 @@ static void complete_cmd( const wchar_t *cmd,
|
|||
|
||||
al_init( &tmp );
|
||||
|
||||
expand_string( nxt_completion,
|
||||
if( expand_string( nxt_completion,
|
||||
&tmp,
|
||||
ACCEPT_INCOMPLETE | DIRECTORIES_ONLY );
|
||||
ACCEPT_INCOMPLETE | DIRECTORIES_ONLY ) != EXPAND_ERROR )
|
||||
{
|
||||
|
||||
for( i=0; i<al_get_count(&tmp); i++ )
|
||||
{
|
||||
|
@ -1310,6 +1314,7 @@ static void complete_cmd( const wchar_t *cmd,
|
|||
free(nxt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
al_destroy( &tmp );
|
||||
|
||||
|
|
|
@ -300,6 +300,12 @@ Example:
|
|||
|
||||
<code>???</code> matches any file in the current directory whose name is exactly three characters long.
|
||||
|
||||
If no matches are founf for a specific wildcard, it will expand intto
|
||||
zero arguments, i.e. to nothing. If none of the wildcarded arguments
|
||||
sent to a command result in any matches, the command will not be
|
||||
executed. If this happens when using the shell interactively, a
|
||||
warning will also be printed.
|
||||
|
||||
\subsection expand-command-substitution Command substitution
|
||||
|
||||
If a parameter contains a set of parenthesis, the text enclosed by the
|
||||
|
|
2
exec.c
2
exec.c
|
@ -1201,7 +1201,7 @@ int exec_subshell( const wchar_t *cmd,
|
|||
if( !cmd )
|
||||
{
|
||||
debug( 1,
|
||||
L"Sent null command to subshell. This is a fish bug. If it can be reproduced, please send a bug report to %ls",
|
||||
L"Sent null command to subshell. This is a fish bug. If it can be reproduced, please send a bug report to %s",
|
||||
PACKAGE_BUGREPORT );
|
||||
return 0;
|
||||
}
|
||||
|
|
40
expand.c
40
expand.c
|
@ -1390,11 +1390,14 @@ int expand_string( wchar_t *str,
|
|||
|
||||
int i;
|
||||
int subshell_ok = 1;
|
||||
int res = EXPAND_OK;
|
||||
|
||||
|
||||
|
||||
if( (!(flags & ACCEPT_INCOMPLETE)) && is_clean( str ) )
|
||||
{
|
||||
al_push( end_out, str );
|
||||
return 1;
|
||||
return EXPAND_OK;
|
||||
}
|
||||
|
||||
al_init( &list1 );
|
||||
|
@ -1416,7 +1419,7 @@ int expand_string( wchar_t *str,
|
|||
free( str );
|
||||
al_destroy( &list1 );
|
||||
al_destroy( &list2 );
|
||||
return 0;
|
||||
return EXPAND_ERROR;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
@ -1430,7 +1433,7 @@ int expand_string( wchar_t *str,
|
|||
if( !subshell_ok )
|
||||
{
|
||||
al_destroy( &list1 );
|
||||
return 0;
|
||||
return EXPAND_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1464,7 +1467,7 @@ int expand_string( wchar_t *str,
|
|||
{
|
||||
al_destroy( in );
|
||||
al_destroy( out );
|
||||
return 0;
|
||||
return EXPAND_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1481,7 +1484,7 @@ int expand_string( wchar_t *str,
|
|||
{
|
||||
al_destroy( in );
|
||||
al_destroy( out );
|
||||
return 0;
|
||||
return EXPAND_ERROR;
|
||||
}
|
||||
}
|
||||
al_truncate( in, 0 );
|
||||
|
@ -1496,17 +1499,22 @@ int expand_string( wchar_t *str,
|
|||
{
|
||||
al_destroy( in );
|
||||
al_destroy( out );
|
||||
return 0;
|
||||
return EXPAND_ERROR;
|
||||
}
|
||||
|
||||
if( flags & ACCEPT_INCOMPLETE )
|
||||
{
|
||||
if( *next == PROCESS_EXPAND )
|
||||
{
|
||||
/*
|
||||
If process expantion matches, we are not
|
||||
interested in other completions, so we
|
||||
short-circut and return
|
||||
*/
|
||||
expand_pid( next, flags, end_out );
|
||||
al_destroy( in );
|
||||
al_destroy( out );
|
||||
return 1;
|
||||
return EXPAND_OK;
|
||||
}
|
||||
else
|
||||
al_push( out, next );
|
||||
|
@ -1517,7 +1525,7 @@ int expand_string( wchar_t *str,
|
|||
{
|
||||
al_destroy( in );
|
||||
al_destroy( out );
|
||||
return 0;
|
||||
return EXPAND_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1550,19 +1558,20 @@ int expand_string( wchar_t *str,
|
|||
case 0:
|
||||
if( !(flags & ACCEPT_INCOMPLETE) )
|
||||
{
|
||||
break;
|
||||
if( res == EXPAND_OK )
|
||||
res = EXPAND_WILDCARD_NO_MATCH;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
res = EXPAND_WILDCARD_MATCH;
|
||||
sort_list( out );
|
||||
al_push_all( end_out, out );
|
||||
al_truncate( out, 0 );
|
||||
break;
|
||||
|
||||
default:
|
||||
fwprintf( stderr, L"error\n" );
|
||||
/*al_destroy( &list1 );*/
|
||||
/*al_destroy( &list2 );*/
|
||||
/*return 0;*/
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1577,7 +1586,8 @@ int expand_string( wchar_t *str,
|
|||
al_destroy( out );
|
||||
}
|
||||
|
||||
return 1;
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
18
expand.h
18
expand.h
|
@ -84,6 +84,23 @@ enum
|
|||
}
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
These are the possible return values for expand_string
|
||||
*/
|
||||
enum
|
||||
{
|
||||
/** Error */
|
||||
EXPAND_ERROR,
|
||||
/** Ok */
|
||||
EXPAND_OK,
|
||||
/** Ok, a wildcard in the string matched no files */
|
||||
EXPAND_WILDCARD_NO_MATCH,
|
||||
/* Ok, a wildcard in the string matched a file */
|
||||
EXPAND_WILDCARD_MATCH
|
||||
}
|
||||
;
|
||||
|
||||
/** Character for separating two array elements. We use 30, i.e. the ascii record separator since that seems logical. */
|
||||
#define ARRAY_SEP 0x1e
|
||||
|
||||
|
@ -111,6 +128,7 @@ enum
|
|||
\param in The parameter to expand
|
||||
\param flag Specifies if any expantion pass should be skipped. Legal values are any combination of EXPAND_SKIP_SUBSHELL EXPAND_SKIP_VARIABLES and EXPAND_SKIP_WILDCARDS
|
||||
\param out The list to which the result will be appended.
|
||||
\return One of EXPAND_OK, EXPAND_ERROR, EXPAND_WILDCARD_MATCH and EXPAND_WILDCARD_NO_MATCH
|
||||
*/
|
||||
int expand_string( wchar_t *in, array_list_t *out, int flag );
|
||||
|
||||
|
|
92
parser.c
92
parser.c
|
@ -98,6 +98,11 @@ The fish parser. Contains functions for parsing code.
|
|||
*/
|
||||
#define CMD_ERR_MSG L"Expected command"
|
||||
|
||||
/**
|
||||
Error message for wildcards with no matches
|
||||
*/
|
||||
#define WILDCARD_ERR_MSG L"Warning: No match for wildcard "
|
||||
|
||||
/** Last error code */
|
||||
int error_code;
|
||||
|
||||
|
@ -152,23 +157,23 @@ static int parse_job( process_t *p,
|
|||
typedef struct
|
||||
{
|
||||
/**
|
||||
Time spent executing the specified command, including parse time for nested blocks
|
||||
Time spent executing the specified command, including parse time for nested blocks.
|
||||
*/
|
||||
int exec;
|
||||
/**
|
||||
Time spent parsing the specified command, incvluding execution time for command substitutions
|
||||
Time spent parsing the specified command, including execution time for command substitutions.
|
||||
*/
|
||||
int parse;
|
||||
/**
|
||||
The block level of the specified command
|
||||
The block level of the specified command. nested blocks and command substitutions both increase the block level.
|
||||
*/
|
||||
int level;
|
||||
/**
|
||||
If the execution of this command was skipped
|
||||
If the execution of this command was skipped.
|
||||
*/
|
||||
int skipped;
|
||||
/**
|
||||
The command string
|
||||
The command string.
|
||||
*/
|
||||
wchar_t *cmd;
|
||||
} profile_element_t;
|
||||
|
@ -757,6 +762,12 @@ static void print_errors()
|
|||
{
|
||||
int tmp;
|
||||
|
||||
/*
|
||||
Wildcard warnings are only printed in interactive mode
|
||||
*/
|
||||
if( ( error_code == WILDCARD_ERROR ) && !is_interactive )
|
||||
return;
|
||||
|
||||
|
||||
debug( 0, L"%ls", err_str );
|
||||
|
||||
|
@ -791,10 +802,20 @@ int eval_args( const wchar_t *line, array_list_t *args )
|
|||
switch(tok_last_type( &tok ) )
|
||||
{
|
||||
case TOK_STRING:
|
||||
if( !expand_string( wcsdup(tok_last( &tok )), args, 0 ) )
|
||||
switch( expand_string( wcsdup(tok_last( &tok )), args, 0 ) )
|
||||
{
|
||||
case EXPAND_ERROR:
|
||||
{
|
||||
err_pos=tok_get_pos( &tok );
|
||||
do_loop=0;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -948,6 +969,11 @@ static void parse_job_main_loop( process_t *p,
|
|||
|
||||
int proc_is_count=0;
|
||||
|
||||
int matched_wildcard = 0, unmatched_wildcard = 0;
|
||||
|
||||
wchar_t *unmatched = 0;
|
||||
int unmatched_pos=0;
|
||||
|
||||
/*
|
||||
Test if this is the 'count' command. We need to special case
|
||||
count, since it should display a help message on 'count .h',
|
||||
|
@ -1045,10 +1071,10 @@ static void parse_job_main_loop( process_t *p,
|
|||
wcscpy( p->actual_cmd, L"count" );
|
||||
}
|
||||
|
||||
if( !expand_string( wcsdup(tok_last( tok )),
|
||||
args,
|
||||
0 )
|
||||
)
|
||||
|
||||
switch( expand_string( wcsdup(tok_last( tok )), args, 0 ) )
|
||||
{
|
||||
case EXPAND_ERROR:
|
||||
{
|
||||
err_pos=tok_get_pos( tok );
|
||||
if( error_code == 0 )
|
||||
|
@ -1058,7 +1084,34 @@ static void parse_job_main_loop( process_t *p,
|
|||
tok_last(tok),
|
||||
tok_get_pos( tok ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EXPAND_WILDCARD_NO_MATCH:
|
||||
{
|
||||
unmatched_wildcard = 1;
|
||||
if( !unmatched )
|
||||
{
|
||||
unmatched = wcsdup(tok_last( tok ));
|
||||
unmatched_pos = tok_get_pos( tok );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EXPAND_WILDCARD_MATCH:
|
||||
{
|
||||
matched_wildcard = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case EXPAND_OK:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1205,6 +1258,19 @@ static void parse_job_main_loop( process_t *p,
|
|||
|
||||
tok_next( tok );
|
||||
}
|
||||
|
||||
if( !error_code )
|
||||
{
|
||||
if( unmatched_wildcard && !matched_wildcard )
|
||||
{
|
||||
error_arg( WILDCARD_ERROR,
|
||||
WILDCARD_ERR_MSG,
|
||||
unmatched,
|
||||
unmatched_pos );
|
||||
}
|
||||
}
|
||||
free( unmatched );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1240,6 +1306,7 @@ static int parse_job( process_t *p,
|
|||
switch( tok_last_type( tok ))
|
||||
{
|
||||
case TOK_STRING:
|
||||
{
|
||||
nxt = expand_one( wcsdup(tok_last( tok )),
|
||||
EXPAND_SKIP_SUBSHELL | EXPAND_SKIP_VARIABLES);
|
||||
if( nxt == 0 )
|
||||
|
@ -1252,6 +1319,7 @@ static int parse_job( process_t *p,
|
|||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_ERROR:
|
||||
{
|
||||
|
@ -1265,6 +1333,7 @@ static int parse_job( process_t *p,
|
|||
}
|
||||
|
||||
default:
|
||||
{
|
||||
error_arg( SYNTAX_ERROR,
|
||||
L"Expected a command name, got token of type ",
|
||||
tok_get_desc( tok_last_type(tok)),
|
||||
|
@ -1272,6 +1341,7 @@ static int parse_job( process_t *p,
|
|||
al_destroy( &args );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int mark = tok_get_pos( tok );
|
||||
|
||||
|
@ -1377,7 +1447,7 @@ static int parse_job( process_t *p,
|
|||
int new_block = 0;
|
||||
tok_next( tok );
|
||||
|
||||
if( (current_block->type != WHILE) )
|
||||
if( ( current_block->type != WHILE ) )
|
||||
{
|
||||
new_block = 1;
|
||||
}
|
||||
|
|
24
parser.h
24
parser.h
|
@ -125,12 +125,34 @@ enum while_status
|
|||
*/
|
||||
enum parser_error
|
||||
{
|
||||
/**
|
||||
No error
|
||||
*/
|
||||
NO_ERR=0,
|
||||
/**
|
||||
An error in the syntax
|
||||
*/
|
||||
SYNTAX_ERROR,
|
||||
/**
|
||||
Error occured while evaluating commands
|
||||
*/
|
||||
EVAL_ERROR,
|
||||
/**
|
||||
Out of memory error
|
||||
*/
|
||||
OOM,
|
||||
/**
|
||||
Stack inconsistency error
|
||||
*/
|
||||
STACK_ERROR,
|
||||
SUBSHELL_ERROR
|
||||
/**
|
||||
Error while evaluating subshell
|
||||
*/
|
||||
SUBSHELL_ERROR,
|
||||
/**
|
||||
No files matching wildcards where found
|
||||
*/
|
||||
WILDCARD_ERROR
|
||||
}
|
||||
;
|
||||
|
||||
|
|
18
wgetopt.c
18
wgetopt.c
|
@ -7,12 +7,18 @@
|
|||
internal commands use wide characters and hence this library is
|
||||
useful.
|
||||
|
||||
If you want to use this version of getopt in your program, simply
|
||||
copy wgetopt.c and wgetopt.h into your program, include wgetopt.h,
|
||||
and use all the regular getopt functions, prefixing every
|
||||
function, global variable and structure with a 'w', and use only
|
||||
wide character strings. There are no other functional changes in
|
||||
this version of getopt besides using wide character strings.
|
||||
If you want to use this version of getopt in your program,
|
||||
download the fish sourcecode, available at <a
|
||||
href='http://roo.no-ip.org/fish/'>the fish homepage</a>. Extract
|
||||
the sourcode, copy wgetopt.c and wgetopt.h into your program
|
||||
directory, include wgetopt.h in your program, and use all the
|
||||
regular getopt functions, prefixing every function, global
|
||||
variable and structure with a 'w', and use only wide character
|
||||
strings. There are no other functional changes in this version of
|
||||
getopt besides using wide character strings.
|
||||
|
||||
For examples of how to use wgetopt, see the fish builtin
|
||||
functions, many of which are defined in builtin.c.
|
||||
|
||||
*/
|
||||
|
||||
|
|
18
wgetopt.h
18
wgetopt.h
|
@ -7,12 +7,18 @@
|
|||
internal commands use wide characters and hence this library is
|
||||
useful.
|
||||
|
||||
If you want to use this version of getopt in your program, simply
|
||||
copy wgetopt.c and wgetopt.h into your program, include wgetopt.h,
|
||||
and use all the regular getopt functions, prefixing every
|
||||
function, global variable and structure with a 'w', and use only
|
||||
wide character strings. There are no other functional changes in
|
||||
this version of getopt besides using wide character strings.
|
||||
If you want to use this version of getopt in your program,
|
||||
download the fish sourcecode, available at <a
|
||||
href='http://roo.no-ip.org/fish/'>the fish homepage</a>. Extract
|
||||
the sourcode, copy wgetopt.c and wgetopt.h into your program
|
||||
directory, include wgetopt.h in your program, and use all the
|
||||
regular getopt functions, prefixing every function, global
|
||||
variable and structure with a 'w', and use only wide character
|
||||
strings. There are no other functional changes in this version of
|
||||
getopt besides using wide character strings.
|
||||
|
||||
For examples of how to use wgetopt, see the fish builtin
|
||||
functions, many of which are defined in builtin.c.
|
||||
|
||||
*/
|
||||
|
||||
|
|
Loading…
Reference in a new issue