diff --git a/Makefile.in b/Makefile.in index 1d81aa1bf..0e874a452 100644 --- a/Makefile.in +++ b/Makefile.in @@ -328,6 +328,9 @@ tokenize: tokenize.o doc_src/tokenize.c tokenizer_test: tokenizer.c tokenizer.h util.o wutil.o common.o $(CC) ${CFLAGS} tokenizer.c util.o wutil.o common.o -D TOKENIZER_TEST $(LDFLAGS) -o $@ +key_reader: key_reader.o input_common.o common.o env_universal.o env_universal_common.o util.o wutil.o + $(CC) key_reader.o input_common.o common.o env_universal.o env_universal_common.o util.o wutil.o $(LDFLAGS) -o $@ + depend: makedepend -fMakefile.in -Y *.c diff --git a/builtin_set.c b/builtin_set.c index a7c7092db..20e9dfe81 100644 --- a/builtin_set.c +++ b/builtin_set.c @@ -234,7 +234,7 @@ static void print_variables(int include_values, int escape, int scope) for( i = 0; i < al_get_count(&names); i++ ) { - wchar_t *key = al_get( &names, i ); + wchar_t *key = (wchar_t *)al_get( &names, i ); /* Why does expand_escape free its argument ?! */ wchar_t *e_key = escape ? expand_escape(wcsdup(key), 1) : wcsdup(key); sb_append(sb_out, e_key); @@ -283,13 +283,16 @@ int builtin_set( wchar_t **argv ) { L"universal", no_argument, 0, 'U' } , + { + L"query", no_argument, 0, 'q' + } , { 0, 0, 0, 0 } } ; - wchar_t short_options[] = L"xglenuU"; + wchar_t short_options[] = L"xglenuUq"; int argc = builtin_count_args(argv); @@ -298,7 +301,7 @@ int builtin_set( wchar_t **argv ) */ int local = 0, global = 0, export = 0; int erase = 0, list = 0, unexport=0; - int universal = 0; + int universal = 0, query=0; /* @@ -349,6 +352,9 @@ int builtin_set( wchar_t **argv ) case 'U': universal = 1; break; + case 'q': + query = 1; + break; case '?': return 1; default: @@ -356,6 +362,20 @@ int builtin_set( wchar_t **argv ) } } + if( query && (erase || list || global || local || universal || export || unexport ) ) + { + sb_append2(sb_err, + argv[0], + BUILTIN_ERR_COMBO, + L"\n", + parser_current_line(), + L"\n", + 0); + builtin_print_help( argv[0], sb_err ); + return 1; + } + + /* Check operation and modifiers sanity */ if( erase && list ) { @@ -394,6 +414,22 @@ int builtin_set( wchar_t **argv ) return 1; } + if( query ) + { + /* + Query mode. Return number of specified variables that do not exist. + */ + int i; + for( i=woptind; i axel@liljencrantz.se diff --git a/doc_src/set.txt b/doc_src/set.txt index c1d59ba80..c99af1c80 100644 --- a/doc_src/set.txt +++ b/doc_src/set.txt @@ -7,12 +7,13 @@ The set builtin causes fish to assign the variable VARIABLE_NAME-e or --erase causes the specified environment variables to be erased -- -U or --universal causes the specified environment variable to be made universal. If this option is supplied, the variable will be shared between all the current users fish instances on the current computer, and will be preserved across restarts of the shell. - -g or --global causes the specified environment variable to be made global. If this option is not supplied, the specified variable will dissapear when the current block ends - -l or --local forces the specified environment variable to be made local to the current block, even if the variable already exists and is non-local - -n or --names List only the names of all defined variables -- -x or --export causes the specified environment variable to be exported to child processes +- -q or --query test if the specified variable names are defined. Does not output anything, but the builtins exit status is the number of variables specified that where not defined. - -u or --unexport causes the specified environment not to be exported to child processes +- -U or --universal causes the specified environment variable to be made universal. If this option is supplied, the variable will be shared between all the current users fish instances on the current computer, and will be preserved across restarts of the shell. +- -x or --export causes the specified environment variable to be exported to child processes If set is called with no arguments, the names and values of all environment variables are printed. diff --git a/env.c b/env.c index 5a5ce9794..ea146196f 100644 --- a/env.c +++ b/env.c @@ -38,8 +38,6 @@ #include "reader.h" #include "parser.h" #include "env_universal.h" -#include "env_universal.h" - /** Command used to start fishd @@ -119,6 +117,12 @@ static hash_table_t env_read_only; */ static char **export_arr=0; +/** + Buffer used for storing string contents for export_arr +*/ +static buffer_t export_buffer; + + /** Flag for checking if we need to regenerate the exported variable array @@ -200,6 +204,9 @@ void env_init() char **p; sb_init( &dyn_var ); + + b_init( &export_buffer ); + /* These variables can not be altered directly by the user @@ -275,6 +282,8 @@ void env_destroy() // fwprintf( stderr, L"Filled %d exported vars\n", c1 ); sb_destroy( &dyn_var ); + + b_destroy( &export_buffer ); while( &top->env != global ) env_pop(); @@ -285,13 +294,8 @@ void env_destroy() hash_destroy( global ); free( top ); - if( export_arr != 0 ) - { - for( ptr = export_arr; *ptr; ptr++ ) - free( *ptr ); - - free( export_arr ); - } + free( export_arr ); + } /** @@ -347,7 +351,18 @@ void env_set( const wchar_t *key, if( var_mode & ENV_UNIVERSAL ) { - env_universal_set( key, val ); + int export = 0; + + if( !(var_mode & ENV_EXPORT ) && + !(var_mode & ENV_UNEXPORT ) ) + { + env_universal_get_export( key ); + } + else + export = (var_mode & ENV_EXPORT ); + + env_universal_set( key, val, export ); + return; } @@ -389,7 +404,18 @@ void env_set( const wchar_t *key, { if( env_universal_get( key ) ) { - env_universal_set( key, val ); + int export = 0; + + if( !(var_mode & ENV_EXPORT ) && + !(var_mode & ENV_UNEXPORT ) ) + { + env_universal_get_export( key ); + } + else + export = (var_mode & ENV_EXPORT ); + + env_universal_set( key, val, export ); + return; } else @@ -602,50 +628,6 @@ void env_pop() } } -/** - Recreate the table of global variables used by execv -*/ -static void fill_arr( const void *key, const void *val, void *aux ) -{ - var_entry_t *val_entry = (var_entry_t *)val; - if( val_entry->export ) - { - - c1++; - - wchar_t *wcs_val = wcsdup( val_entry->val ); - wchar_t *pos = wcs_val; - - int *idx_ptr = (int *)aux; - char *key_str = wcs2str((wchar_t *)key); - - char *val_str; - char *woot; - - while( *pos ) - { - if( *pos == ARRAY_SEP ) - *pos = L':'; - pos++; - } - - val_str = wcs2str( wcs_val ); - free( wcs_val ); - - woot = malloc( sizeof(char)*( strlen(key_str) + - strlen(val_str) + 2) ); - - strcpy( woot, key_str ); - strcat( woot, "=" ); - strcat( woot, val_str ); - export_arr[*idx_ptr] = woot; - (*idx_ptr)++; - - free( key_str ); - free( val_str ); - } -} - /** Function used with hash_foreach to insert keys of one table into @@ -660,13 +642,15 @@ static void add_key_to_hash( const void *key, ( !e->export && get_names_show_unexported) ) hash_put( (hash_table_t *)aux, key, 0 ); } -static void add_universal_key_to_hash( const void *key, - const void *data, - void *aux ) + +static void add_to_hash( const void *k, void *aux ) { - hash_put( (hash_table_t *)aux, key, 0 ); + hash_put( (hash_table_t *)aux, + k, + 0 ); } + void env_get_names( array_list_t *l, int flags ) { int show_local = flags & ENV_LOCAL; @@ -718,10 +702,15 @@ void env_get_names( array_list_t *l, int flags ) if( show_universal ) { - if( get_names_show_unexported ) - hash_foreach2( &env_universal_var, - add_universal_key_to_hash, - &names ); + array_list_t uni_list; + al_init( &uni_list ); + + env_universal_get_names( &uni_list, + get_names_show_exported, + get_names_show_unexported ); + + al_foreach2( &uni_list, &add_to_hash, &names ); + al_destroy( &uni_list ); } hash_get_keys( &names, l ); @@ -729,35 +718,116 @@ void env_get_names( array_list_t *l, int flags ) } -char **env_export_arr() +static void export_func1( const void *k, const void *v, void *aux ) { - if( has_changed ) + var_entry_t *val_entry = (var_entry_t *)v; + if( val_entry->export ) { - int pos=0; - char **ptr; - env_node_t *n=top; + hash_table_t *h = (hash_table_t *)aux; - if( export_arr != 0 ) - { - for( ptr = export_arr; *ptr; ptr++ ) - free( *ptr ); - } + if( !hash_get( h, k ) ) + hash_put( h, k, val_entry->val ); + } + +} - export_arr = realloc( export_arr, - sizeof(char *)*(export_count + 1) ); +static void export_func2( const void *k, const void *v, void *aux ) +{ + wchar_t *key = (wchar_t *)k; + wchar_t *val = (wchar_t *)v; + + char *ks = wcs2str( key ); + char *vs = wcs2str( val ); + + char *pos = vs; + + buffer_t *out = (buffer_t *)aux; + + if( !ks || !vs ) + { + die_mem(); + } + + /* + Make arrays into colon-separated lists + */ + while( *pos ) + { + if( *pos == ARRAY_SEP ) + *pos = ':'; + pos++; + } + int nil = 0; + + b_append( out, ks, strlen(ks) ); + b_append( out, "=", 1 ); + b_append( out, vs, strlen(vs) ); + b_append( out, &nil, 1 ); + + free( ks ); + free( vs ); +} + +char **env_export_arr( int recalc) +{ + if( recalc ) + env_universal_barrier(); + + if( has_changed || env_universal_update ) + { + array_list_t uni; + hash_table_t vals; + env_node_t *n=top; + int prev_was_null=1; + int pos=0; + int i; + + debug( 3, L"env_export_arr()" ); + + hash_init( &vals, &hash_wcs_func, &hash_wcs_cmp ); while( n ) { - hash_foreach2( &n->env, &fill_arr, &pos ); + hash_foreach2( &n->env, &export_func1, &vals ); if( n->new_scope ) n = global_env; else - n = n->next; - + n = n->next; } + + al_init( &uni ); + env_universal_get_names( &uni, 1, 0 ); + for( i=0; i= 0 ) { - barrier(); + env_universal_barrier(); } debug( 2, L"end env_universal_init()" ); } @@ -208,22 +234,13 @@ int env_universal_read_all() init = 1; if( env_universal_server.fd >= 0 ) - barrier(); + env_universal_barrier(); } if( env_universal_server.fd != -1 ) { read_message( &env_universal_server ); - if( env_universal_server.killme ) - { - debug( 2, L"Lost connection to universal variable server." ); - close( env_universal_server.fd ); - env_universal_server.fd = -1; - env_universal_server.killme=0; - sb_clear( &env_universal_server.input ); - - env_universal_read_all(); - } + check_connection(); return 1; } else @@ -235,40 +252,59 @@ int env_universal_read_all() wchar_t *env_universal_get( const wchar_t *name ) { + debug( 3, L"env_universal_get( %ls )", name ); if( !init) return 0; - debug( 2, L"env_universal_get( %ls )", name ); - barrier(); - if( !name ) return 0; - return (wchar_t *)hash_get( &env_universal_var, name ); + env_universal_barrier(); + + return env_universal_common_get( name ); } -static void barrier() +int env_universal_get_export( const wchar_t *name ) +{ + return env_universal_common_get_export( name ); +} + +void env_universal_barrier() { message_t *msg; fd_set fds; + + if( !init ) + return; barrier_reply = 0; + /* + Create barrier request + */ msg= create_message( BARRIER, 0, 0); msg->count=1; q_put( &env_universal_server.unsent, msg ); + /* + Wait until barrier request has been sent + */ debug( 3, L"Create barrier" ); while( 1 ) { try_send_all( &env_universal_server ); + check_connection(); + if( q_empty( &env_universal_server.unsent ) ) break; FD_ZERO( &fds ); FD_SET( env_universal_server.fd, &fds ); select( env_universal_server.fd+1, 0, &fds, 0, 0 ); } - + + /* + Wait for barrier reply + */ debug( 3, L"Sent barrier request" ); while( !barrier_reply ) { @@ -278,25 +314,31 @@ static void barrier() env_universal_read_all(); } debug( 3, L"End barrier" ); - } -void env_universal_set( const wchar_t *name, const wchar_t *value ) +void env_universal_set( const wchar_t *name, const wchar_t *value, int export ) { message_t *msg; if( !init ) return; - debug( 2, L"env_universal_set( %ls, %ls )", name, value ); + debug( 3, L"env_universal_set( %ls, %ls )", name, value ); + + msg = create_message( export?SET_EXPORT:SET, + name, + value); - msg= create_message( SET, name, value); + if( !msg ) + { + debug( 1, L"Could not create universal variable message" ); + return; + } + msg->count=1; q_put( &env_universal_server.unsent, msg ); - barrier(); - - + env_universal_barrier(); } void env_universal_remove( const wchar_t *name ) @@ -312,5 +354,14 @@ void env_universal_remove( const wchar_t *name ) msg= create_message( ERASE, name, 0); msg->count=1; q_put( &env_universal_server.unsent, msg ); - barrier(); + env_universal_barrier(); +} + +void env_universal_get_names( array_list_t *l, + int show_exported, + int show_unexported ) +{ + env_universal_common_get_names( l, + show_exported, + show_unexported ); } diff --git a/env_universal.h b/env_universal.h index 6705febd6..48cbef7b0 100644 --- a/env_universal.h +++ b/env_universal.h @@ -12,6 +12,11 @@ */ extern connection_t env_universal_server; +/** + Update flag. Set to 1 whenever an update has occured. +*/ +extern int env_universal_update; + /** Initialize the envuni library */ @@ -25,10 +30,17 @@ void env_universal_destroy(); Get the value of a universal variable */ wchar_t *env_universal_get( const wchar_t *name ); + +/** + Get the export flag of the variable with the specified + name. Returns 0 if the variable doesn't exist. +*/ +int env_universal_get_export( const wchar_t *name ); + /** Set the value of a universal variable */ -void env_universal_set( const wchar_t *name, const wchar_t *val ); +void env_universal_set( const wchar_t *name, const wchar_t *val, int export ); /** Erase a universal variable */ @@ -36,4 +48,10 @@ void env_universal_remove( const wchar_t *name ); int env_universal_read_all(); +void env_universal_get_names( array_list_t *l, + int show_exported, + int show_unexported ); + +void env_universal_barrier(); + #endif diff --git a/env_universal_common.c b/env_universal_common.c index de81f197c..6aa42810d 100644 --- a/env_universal_common.c +++ b/env_universal_common.c @@ -35,12 +35,24 @@ */ #define SET_MBS "SET" +/** + Non-wide version of the set_export command +*/ +#define SET_EXPORT_MBS "SET_EXPORT" + /** Non-wide version of the erase command */ #define ERASE_MBS "ERASE" +/** + Non-wide version of the barrier command +*/ #define BARRIER_MBS "BARRIER" + +/** + Non-wide version of the barrier_reply command +*/ #define BARRIER_REPLY_MBS "BARRIER_REPLY" /** @@ -48,6 +60,19 @@ */ #define PARSE_ERR L"Unable to parse universal variable message: '%ls'" +/** + A variable entry. Stores the value of a variable and whether it + should be exported. Obviously, it needs to be allocated large + enough to fit the value string. +*/ +typedef struct var_entry +{ + int export; /**< Whether the variable should be exported */ + wchar_t val[0]; /**< The value of the variable */ +} +var_entry_t; + + static void parse_message( wchar_t *msg, connection_t *src ); @@ -61,6 +86,17 @@ void (*callback)( int type, const wchar_t *val ); +/** + Variable used by env_get_names to communicate auxiliary information + to add_key_to_hash +*/ +static int get_names_show_exported; +/** + Variable used by env_get_names to communicate auxiliary information + to add_key_to_hash +*/ +static int get_names_show_unexported; + void env_universal_common_init( void (*cb)(int type, const wchar_t *key, const wchar_t *val ) ) { @@ -155,6 +191,7 @@ static int match( const wchar_t *msg, const wchar_t *cmd ) size_t len = wcslen( cmd ); if( wcsncasecmp( msg, cmd, len ) != 0 ) return 0; + if( msg[len] && msg[len]!= L' ' && msg[len] != L'\t' ) return 0; @@ -169,12 +206,13 @@ static void parse_message( wchar_t *msg, if( msg[0] == L'#' ) return; - - if( match( msg, SET_STR ) ) + + if( match( msg, SET_STR ) || match( msg, SET_EXPORT_STR )) { wchar_t *name, *val, *tmp; - - name = msg+wcslen(SET_STR); + int export = match( msg, SET_EXPORT_STR ); + + name = msg+(export?wcslen(SET_EXPORT_STR):wcslen(SET_STR)); while( wcschr( L"\t ", *name ) ) name++; @@ -189,14 +227,22 @@ static void parse_message( wchar_t *msg, val = unescape( wcsdup(val), 0 ); + var_entry_t *entry = + malloc( sizeof(var_entry_t) + sizeof(wchar_t)*(wcslen(val)+1) ); + if( !entry ) + die_mem(); + entry->export=export; + + wcscpy( entry->val, val ); remove_entry( key ); - hash_put( &env_universal_var, key, val ); + hash_put( &env_universal_var, key, entry ); if( callback ) { - callback( SET, key, val ); + callback( export?SET_EXPORT:SET, key, val ); } + free(val ); } else { @@ -205,7 +251,7 @@ static void parse_message( wchar_t *msg, } else if( match( msg, ERASE_STR ) ) { - wchar_t *name, *val, *tmp; + wchar_t *name, *tmp; name = msg+wcslen(ERASE_STR); while( wcschr( L"\t ", *name ) ) @@ -253,8 +299,11 @@ int try_send( message_t *msg, int fd ) { + debug( 3, + L"before write of %d chars to fd %d", strlen(msg->body), fd ); + int res = write( fd, msg->body, strlen(msg->body) ); - + if( res == -1 ) { switch( errno ) @@ -282,12 +331,11 @@ int try_send( message_t *msg, void try_send_all( connection_t *c ) { - debug( 2, + debug( 3, L"Send all updates to connection on fd %d", c->fd ); while( !q_empty( &c->unsent) ) { - switch( try_send( (message_t *)q_peek( &c->unsent), c->fd ) ) { case 1: @@ -295,9 +343,13 @@ void try_send_all( connection_t *c ) break; case 0: + debug( 1, + L"Socket full, send rest later" ); return; case -1: + debug( 1, + L"Socket dead!!!" ); c->killme = 1; return; } @@ -329,6 +381,7 @@ message_t *create_message( int type, switch( type ) { case SET: + case SET_EXPORT: { if( !val_in ) { @@ -341,20 +394,20 @@ message_t *create_message( int type, char *val = wcs2str(esc ); free(esc); - - - sz = strlen(SET_MBS) + strlen(key) + strlen(val) + 4; + + sz = strlen(type==SET?SET_MBS:SET_EXPORT_MBS) + strlen(key) + strlen(val) + 4; msg = malloc( sizeof( message_t ) + sz ); - + if( !msg ) die_mem(); - - strcpy( msg->body, SET_MBS " " ); + + strcpy( msg->body, (type==SET?SET_MBS:SET_EXPORT_MBS) ); + strcat( msg->body, " " ); strcat( msg->body, key ); strcat( msg->body, ":" ); strcat( msg->body, val ); strcat( msg->body, "\n" ); - + free( val ); break; @@ -406,3 +459,68 @@ message_t *create_message( int type, msg->count=0; return msg; } + +/** + Function used with hash_foreach to insert keys of one table into + another +*/ +static void add_key_to_hash( const void *key, + const void *data, + void *aux ) +{ + var_entry_t *e = (var_entry_t *)data; + if( ( e->export && get_names_show_exported) || + ( !e->export && get_names_show_unexported) ) + al_push( (array_list_t *)aux, key ); +} + +void env_universal_common_get_names( array_list_t *l, + int show_exported, + int show_unexported ) +{ + get_names_show_exported = show_exported; + get_names_show_unexported = show_unexported; + + hash_foreach2( &env_universal_var, + add_key_to_hash, + l ); +} + +wchar_t *env_universal_common_get( const wchar_t *name ) +{ + var_entry_t *e = (var_entry_t *)hash_get( &env_universal_var, name ); + if( e ) + return e->val; + return 0; +} + +int env_universal_common_get_export( const wchar_t *name ) +{ + var_entry_t *e = (var_entry_t *)hash_get( &env_universal_var, name ); + if( e ) + return e->export; + return 0; +} + +static void enqueue( const void *k, + const void *v, + void *q) +{ + const wchar_t *key = (const wchar_t *)k; + const var_entry_t *val = (const var_entry_t *)v; + queue_t *queue = (queue_t *)q; + + message_t *msg = create_message( val->export?SET_EXPORT:SET, key, val->val ); + msg->count=1; + + q_put( queue, msg ); +} + +void enqueue_all( connection_t *c ) +{ + hash_foreach2( &env_universal_var, + &enqueue, + (void *)&c->unsent ); + try_send_all( c ); +} + diff --git a/env_universal_common.h b/env_universal_common.h index 3b53273be..286da9c6f 100644 --- a/env_universal_common.h +++ b/env_universal_common.h @@ -7,12 +7,24 @@ */ #define SET_STR L"SET" +/** + The set_export command +*/ +#define SET_EXPORT_STR L"SET_EXPORT" + /** The erase command */ #define ERASE_STR L"ERASE" +/** + The barrier command +*/ #define BARRIER_STR L"BARRIER" + +/** + The barrier_reply command +*/ #define BARRIER_REPLY_STR L"BARRIER_REPLY" @@ -27,17 +39,13 @@ enum { SET, + SET_EXPORT, ERASE, BARRIER, BARRIER_REPLY, } ; -/** - The table of universal variables -*/ -extern hash_table_t env_universal_var; - /** This struct represents a connection between a universal variable server/client */ @@ -107,4 +115,25 @@ void env_universal_common_init(void (*cb)(int type, const wchar_t *key, const wc */ void env_universal_common_destroy(); +/** + Add all variable names to the specified list +*/ +void env_universal_common_get_names( array_list_t *l, + int show_exported, + int show_unexported ); + +/** + Get the value of the variable with the specified name +*/ +wchar_t *env_universal_common_get( const wchar_t *name ); + +/** + Get the export flag of the variable with the specified + name. Returns 0 if the variable doesn't exist. +*/ +int env_universal_common_get_export( const wchar_t *name ); + +void enqueue_all( connection_t *c ); + + #endif diff --git a/exec.c b/exec.c index 08f4f83df..c280aba08 100644 --- a/exec.c +++ b/exec.c @@ -289,7 +289,7 @@ static void launch_process( process_t *p ) /* Set the standard input/output channels of the new process. */ - execve (wcs2str(p->actual_cmd), wcsv2strv( (const wchar_t **) p->argv), env_export_arr() ); + execve (wcs2str(p->actual_cmd), wcsv2strv( (const wchar_t **) p->argv), env_export_arr( 0 ) ); debug( 0, L"Failed to execute process %ls", p->actual_cmd ); @@ -659,7 +659,6 @@ void exec( job_t *j ) int skip_fork; /* This call is used so the global environment variable array is regenerated, if needed, before the fork. That way, we avoid a lot of duplicate work where EVERY child would need to generate it */ - env_export_arr(); io_data_t pipe_read, pipe_write; io_data_t *tmp; @@ -720,6 +719,10 @@ void exec( job_t *j ) { mypipe[1]=-1; skip_fork=0; + + if( p->type == EXTERNAL ) + env_export_arr( 1 ); + /* Set up fd:s that will be used in the pipe diff --git a/fishd.c b/fishd.c index 30e93b8b8..2cf4e5995 100644 --- a/fishd.c +++ b/fishd.c @@ -107,48 +107,29 @@ int get_socket() return s; } -void enqueue( const void *k, - const void *v, - void *q) -{ - const wchar_t *key = (const wchar_t *)k; - const wchar_t *val = (const wchar_t *)v; - queue_t *queue = (queue_t *)q; - - message_t *msg = create_message( SET, key, val ); - msg->count=1; - - q_put( queue, msg ); -} - -void enqueue_all( connection_t *c ) -{ - hash_foreach2( &env_universal_var, - &enqueue, - (void *)&c->unsent ); - try_send_all( c ); -} - void broadcast( int type, const wchar_t *key, const wchar_t *val ) { connection_t *c; message_t *msg; + debug( 1, L"Got message %d %ls %ls", type, key, val ); + if( !conn ) return; - - msg = create_message( type, key, val ); + + msg = create_message( type, key, val ); + /* Don't merge loops, or try_send_all can free the message prematurely */ - + for( c = conn; c; c=c->next ) { msg->count++; q_put( &c->unsent, msg ); } - + for( c = conn; c; c=c->next ) { try_send_all( c ); diff --git a/init/completions/set.fish b/init/completions/set.fish index 57e860ab1..183d0932e 100644 --- a/init/completions/set.fish +++ b/init/completions/set.fish @@ -7,6 +7,7 @@ complete -c set -s u -l unexport -d "Do not export variable to subprocess" complete -c set -s g -l global -d "Make variable scope global" complete -c set -s l -l local -d "Make variable scope local" complete -c set -s U -l universal -d "Make variable scope universal, i.e. shared between all fish terminals" +complete -c set -s q -l query -d "Test if variable is defined" complete -c set -s h -l help -d "Display help and exit" function __fish_set_is_first -d 'Test if no non-switch argument has been specified yet' diff --git a/init/completions/wget.fish b/init/completions/wget.fish index 42bb4ceae..6189461fc 100644 --- a/init/completions/wget.fish +++ b/init/completions/wget.fish @@ -1,3 +1,6 @@ +# +# Completions for the wget command +# complete -c wget -s V -l version -d "Display version and exit" complete -c wget -s h -l help -d "Display help and exit" @@ -20,11 +23,11 @@ complete -c wget -l no-clobber -d "Never overwrite files with same name" complete -c wget -o nc -d "Never overwrite files with same name" complete -c wget -s c -l continue -d "Continue getting a partially-downloaded file" complete -c wget -l progress -d "Select progress meter type" -a " -dot\t'Print one dot for every kB of data, 50 dots per line' -dot:default\t'Print one dot for every kB of data, 50 dots per line' -dot:binary\t'Print one dot for every 8 kB of data, 48 dots per line' -dot:mega\t'Print one dot for every 64 kB of data, 48 dots per line' -bar\t'Print progress bar' + dot\t'Print one dot for every kB of data, 50 dots per line' + dot:default\t'Print one dot for every kB of data, 50 dots per line' + dot:binary\t'Print one dot for every 8 kB of data, 48 dots per line' + dot:mega\t'Print one dot for every 64 kB of data, 48 dots per line' + bar\t'Print progress bar' " complete -c wget -s N -l timestamping -d "Turn on time-stamping" complete -c wget -s S -l server-response -d "Print the headers/responses sent by servers" @@ -41,8 +44,8 @@ complete -c wget -s Y -l proxy -d "Toggle proxy support" -xa "on off" complete -c wget -s Q -l quota -d "Specify download quota for automatic retrievals" -x complete -c wget -l dns-cache -d "Turn off caching of DNS lookups" -xa "off" complete -c wget -l restrict-file-names -d "Change which characters found in remote URLs may show up in local file names" -a " -unix\t'Escape slash and non-printing characters' -windows\t'Escape most non-alphabetical characters' + unix\t'Escape slash and non-printing characters' + windows\t'Escape most non-alphabetical characters' " # HTTP options diff --git a/init/completions/yum.fish b/init/completions/yum.fish index 077312510..3acfa5157 100644 --- a/init/completions/yum.fish +++ b/init/completions/yum.fish @@ -1,3 +1,6 @@ +# +# Completions for the yum command +# #Load rpm completions, since that is where the package completion function is defined complete -y rpm diff --git a/init/fish_interactive.fish b/init/fish_interactive.fish index 14b389a9e..c2a307614 100644 --- a/init/fish_interactive.fish +++ b/init/fish_interactive.fish @@ -53,12 +53,19 @@ end # Set various color values # -function set_default -d "Set a universal variable, unless it has already been set" - if not test $$argv[1] +function set_default -d "Set an universal variable, unless it has already been set" + if not set -q $argv[1] set -U -- $argv end end +function set_exported_default -d "Set an exported universal variable, unless it has already been set" + if not set -q $argv[1] + set -Ux -- $argv + end +end + + # Regular syntax highlighting colors set_default fish_color_normal normal set_default fish_color_command green @@ -83,21 +90,20 @@ set_default fish_pager_color_progress cyan # Directory history colors set_default fish_color_history_current cyan -functions -e set_default # # Setup the CDPATH variable # -set -gx CDPATH . ~ +set_exported_default CDPATH . ~ # # Match colors for grep, if supported # if grep --color=auto --help 1>/dev/null 2>/dev/null - set -gx GREP_COLOR '97;45' - set -gx -- GREP_OPTIONS '--color=auto' + set_exported_default GREP_COLOR '97;45' + set_exported_default GREP_OPTIONS '--color=auto' end # @@ -105,6 +111,9 @@ end # if command ls --color=auto --help 1>/dev/null 2>/dev/null - set -gx LS_COLORS $LS_COLORS '*.jar=01;31' '*.doc=35' '*.pdf=35' '*.ps=35' '*.xls=35' '*.swf=35' '*~=37' + set_exported_default LS_COLORS $LS_COLORS '*.jar=01;31' '*.doc=35' '*.pdf=35' '*.ps=35' '*.xls=35' '*.swf=35' '*~=37' end + +functions -e set_default +functions -e set_exported_default diff --git a/key_reader.c b/key_reader.c index bfaaf8094..2dbb0c1ae 100644 --- a/key_reader.c +++ b/key_reader.c @@ -12,17 +12,7 @@ #include #include -static int readch() -{ - char arr[1]; - if( read( 0, arr, 1 ) < 0 ) - { - perror( "read" ); - return readch(); - } - else - return arr[0]; -} +#include "input_common.h" int writestr( char *str ) { @@ -66,6 +56,9 @@ int main( int argc, char **argv) struct termios modes, /* so we can change the modes */ savemodes; /* so we can reset the modes when we're done */ + input_common_init(0); + + tcgetattr(0,&modes); /* get the current terminal modes */ savemodes = modes; /* save a copy so we can reset them */ @@ -76,9 +69,9 @@ int main( int argc, char **argv) tcsetattr(0,TCSANOW,&modes); /* set the new modes */ while(1) { - if( (c=readch()) == EOF ) + if( (c=input_common_readch(0)) == EOF ) break; - if((c > 31) && (c != 127) ) + if( (c > 31) && (c != 127) ) sprintf( scratch, "dec: %d hex: %x char: %c\n", c, c, c ); else sprintf( scratch, "dec: %d hex: %x\n", c, c ); @@ -86,6 +79,8 @@ int main( int argc, char **argv) } /* reset the terminal to the saved mode */ tcsetattr(0,TCSANOW,&savemodes); + + input_common_destroy(); } return 0; diff --git a/parser.c b/parser.c index 4925f1689..6a8fa9322 100644 --- a/parser.c +++ b/parser.c @@ -1605,10 +1605,7 @@ static void eval_job( tokenizer *tok ) long long t1=0, t2=0, t3=0; profile_element_t *p=0; int skip = 0; - - if( !is_block && !is_subshell ) - env_universal_read_all(); - + if( profile ) { p=malloc( sizeof(profile_element_t)); diff --git a/proc.c b/proc.c index 53512fe62..86b23a0bb 100644 --- a/proc.c +++ b/proc.c @@ -45,6 +45,7 @@ Some of the code in this file is based on code from the Glibc manual. #include "reader.h" #include "sanity.h" #include "env.h" +#include "parser.h" /** Size of message buffer @@ -540,7 +541,7 @@ static void handle_child_status( pid_t pid, int status ) int found_proc = 0; job_t *j; process_t *p; -// char mess[MESS_SIZE]; + char mess[MESS_SIZE]; found_proc = 0; /* snprintf( mess, @@ -587,13 +588,12 @@ static void handle_child_status( pid_t pid, int status ) } - if( !is_interactive ) + if( WIFSIGNALED( status ) && + ( WTERMSIG(status)==SIGINT || + WTERMSIG(status)==SIGQUIT ) ) { - - if( WIFSIGNALED( status ) && - ( WTERMSIG(status)==SIGINT || - WTERMSIG(status)==SIGQUIT ) ) - { + if( !is_interactive_session ) + { struct sigaction act; sigemptyset( & act.sa_mask ); act.sa_flags=0; @@ -602,6 +602,23 @@ static void handle_child_status( pid_t pid, int status ) sigaction( SIGQUIT, &act, 0 ); kill( getpid(), WTERMSIG(status) ); } + else + { + block_t *c = current_block; + + snprintf( mess, + MESS_SIZE, + "Process %ls from job %ls exited through signal, breaking loops\n", + p->actual_cmd, + j->command ); + write( 2, mess, strlen(mess )); + + while( c ) + { + c->skip=1; + c=c->outer; + } + } } if( !found_proc )