From 9b4c34aa4c95a8d2c6703b7c04443f82f086d359 Mon Sep 17 00:00:00 2001 From: axel Date: Sun, 4 Dec 2005 02:43:56 +1000 Subject: [PATCH] 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 --- complete.c | 53 ++++++++++++----------- doc_src/doc.hdr | 6 +++ exec.c | 2 +- expand.c | 40 ++++++++++------- expand.h | 20 ++++++++- parser.c | 112 +++++++++++++++++++++++++++++++++++++++--------- parser.h | 24 ++++++++++- wgetopt.c | 18 +++++--- wgetopt.h | 18 +++++--- 9 files changed, 218 insertions(+), 75 deletions(-) diff --git a/complete.c b/complete.c index 8088cfe08..b6516b25d 100644 --- a/complete.c +++ b/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), - comp, - ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ); - complete_cmd_desc( cmd, comp ); + if( expand_string( wcsdup(cmd), + comp, + ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR ) + { + complete_cmd_desc( cmd, comp ); + } al_destroy( &tmp ); } else @@ -1237,14 +1239,15 @@ 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 ); - - for( i=0; i??? 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 diff --git a/exec.c b/exec.c index e95023c6b..a2e982a2e 100644 --- a/exec.c +++ b/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; } diff --git a/expand.c b/expand.c index 96b887046..120555e49 100644 --- a/expand.c +++ b/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; + } diff --git a/expand.h b/expand.h index e0bc6e5ac..ae510728a 100644 --- a/expand.h +++ b/expand.h @@ -6,7 +6,7 @@ benefit from using a more clever memory allocation scheme, perhaps an evil combination of talloc, string buffers and reference counting. - + */ #ifndef FISH_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 ); diff --git a/parser.c b/parser.c index 6ef81d258..f44ee0601 100644 --- a/parser.c +++ b/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 ) ) { - err_pos=tok_get_pos( &tok ); - do_loop=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,20 +1071,47 @@ 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 ) ) { - err_pos=tok_get_pos( tok ); - if( error_code == 0 ) + case EXPAND_ERROR: { - error_arg( SYNTAX_ERROR, - L"Could not expand string", - tok_last(tok), - tok_get_pos( tok ) ); + err_pos=tok_get_pos( tok ); + if( error_code == 0 ) + { + error_arg( SYNTAX_ERROR, + L"Could not expand string", + 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,7 +1319,8 @@ static int parse_job( process_t *p, return 0; } break; - + } + case TOK_ERROR: { error_arg( SYNTAX_ERROR, @@ -1265,14 +1333,16 @@ 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)), tok_get_pos( tok ) ); al_destroy( &args ); return 0; + } } - + int mark = tok_get_pos( tok ); if( wcscmp( L"command", nxt )==0 ) @@ -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; } diff --git a/parser.h b/parser.h index cb6170476..fc4fbfe77 100644 --- a/parser.h +++ b/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 } ; diff --git a/wgetopt.c b/wgetopt.c index 229f37086..6a1bd7b2a 100644 --- a/wgetopt.c +++ b/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 the fish homepage. 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. */ diff --git a/wgetopt.h b/wgetopt.h index 9c5c9947a..599b35329 100644 --- a/wgetopt.h +++ b/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 the fish homepage. 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. */