aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile.in3
-rw-r--r--builtin_set.c42
-rw-r--r--doc_src/doc.hdr3
-rw-r--r--doc_src/set.txt5
-rw-r--r--env.c226
-rw-r--r--env.h2
-rw-r--r--env_universal.c107
-rw-r--r--env_universal.h20
-rw-r--r--env_universal_common.c152
-rw-r--r--env_universal_common.h39
-rw-r--r--exec.c7
-rw-r--r--fishd.c33
-rw-r--r--init/completions/set.fish1
-rw-r--r--init/completions/wget.fish17
-rw-r--r--init/completions/yum.fish3
-rw-r--r--init/fish_interactive.fish23
-rw-r--r--key_reader.c21
-rw-r--r--parser.c5
-rw-r--r--proc.c31
19 files changed, 538 insertions, 202 deletions
diff --git a/Makefile.in b/Makefile.in
index 1d81aa1b..0e874a45 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 a7c7092d..20e9dfe8 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);
@@ -284,12 +284,15 @@ 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<argc; i++ )
+ {
+ if( env_get( argv[i] )==0 )
+ retcode++;
+
+ }
+ return retcode;
+ }
+
+
/* Parse destination */
if( woptind < argc )
{
diff --git a/doc_src/doc.hdr b/doc_src/doc.hdr
index 90f36347..a354c2fb 100644
--- a/doc_src/doc.hdr
+++ b/doc_src/doc.hdr
@@ -882,7 +882,8 @@ g++, javac, java, gcj, lpr, doxygen, whois, find)
version of a POSIX command
- Yanking weird characters from clipboard prints Unicode escapes
- Prefix string in completion display is sometimes incorrect
-
+- Pressing escape when doing a token search breaks things
+- Universal variables should be exportable
If you think you have found a bug not described here, please send a
report to <a href="mailto:axel@liljencrantz.se"> axel@liljencrantz.se
diff --git a/doc_src/set.txt b/doc_src/set.txt
index c1d59ba8..c99af1c8 100644
--- a/doc_src/set.txt
+++ b/doc_src/set.txt
@@ -7,12 +7,13 @@ The <tt>set</tt> builtin causes fish to assign the variable <tt>VARIABLE_NAME</t
\subsection set-description Description
- <tt>-e</tt> or <tt>--erase</tt> causes the specified environment variables to be erased
-- <tt>-U</tt> or <tt>--universal</tt> 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.
- <tt>-g</tt> or <tt>--global</tt> 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
- <tt>-l</tt> or <tt>--local</tt> forces the specified environment variable to be made local to the current block, even if the variable already exists and is non-local
- <tt>-n</tt> or <tt>--names</tt> List only the names of all defined variables
-- <tt>-x</tt> or <tt>--export</tt> causes the specified environment variable to be exported to child processes
+- <tt>-q</tt> or <tt>--query</tt> 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.
- <tt>-u</tt> or <tt>--unexport</tt> causes the specified environment not to be exported to child processes
+- <tt>-U</tt> or <tt>--universal</tt> 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.
+- <tt>-x</tt> or <tt>--export</tt> 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 5a5ce979..ea146196 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
@@ -120,6 +118,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<al_get_count( &uni ); i++ )
+ {
+ wchar_t *key = (wchar_t *)al_get( &uni, i );
+ wchar_t *val = env_universal_get( key );
+ if( !hash_get( &vals, key ) )
+ hash_put( &vals, key, val );
+ }
+ al_destroy( &uni );
+
+ export_buffer.used=0;
+
+ hash_foreach2( &vals, &export_func2, &export_buffer );
+ hash_destroy( &vals );
+
+ export_arr = realloc( export_arr,
+ sizeof(char *)*(hash_get_count( &vals) + 1) );
+
+ for( i=0; i<export_buffer.used; i++ )
+ {
+ if( prev_was_null )
+ {
+ export_arr[pos++]= &export_buffer.buff[i];
+ debug( 3, L"%s", &export_buffer.buff[i]);
+ }
+ prev_was_null = (export_buffer.buff[i]==0);
+ }
export_arr[pos]=0;
has_changed=0;
+ env_universal_update=0;
+
}
return export_arr;
}
diff --git a/env.h b/env.h
index 23b9fbf0..36416281 100644
--- a/env.h
+++ b/env.h
@@ -89,7 +89,7 @@ void env_pop();
/**
Returns an array containing all exported variables in a format suitable for execv.
*/
-char **env_export_arr();
+char **env_export_arr( int recalc );
/**
Insert all variable names into l. These are not copies of the strings and should not be freed after use.
diff --git a/env_universal.c b/env_universal.c
index b10d307d..3f73d7b4 100644
--- a/env_universal.c
+++ b/env_universal.c
@@ -41,9 +41,11 @@ wchar_t * path;
wchar_t *user;
void (*start_fishd)();
+int env_universal_update=0;
+
static int barrier_reply = 0;
-static void barrier();
+void env_universal_barrier();
/**
@@ -109,8 +111,12 @@ static int get_socket( int fork_ok )
if( fork_ok )
{
debug( 2, L"Could not connect to socket %d, starting fishd", s );
+
if( start_fishd )
+ {
start_fishd();
+ }
+
return get_socket( 0 );
}
@@ -133,16 +139,36 @@ static int get_socket( int fork_ok )
static void callback( int type, const wchar_t *name, const wchar_t *val )
{
+
if( type == BARRIER_REPLY )
{
debug( 3, L"Got barrier reply" );
-
barrier_reply = 1;
}
+ else
+ {
+ env_universal_update=1;
+ }
+}
+
+static void check_connection()
+{
+ if( !init )
+ return;
+ if( env_universal_server.killme )
+ {
+ debug( 3, 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();
+ }
}
+
void env_universal_init( wchar_t * p, wchar_t *u, void (*sf)() )
{
debug( 2, L"env_universal_init()" );
@@ -160,7 +186,7 @@ void env_universal_init( wchar_t * p, wchar_t *u, void (*sf)() )
init = 1;
if( env_universal_server.fd >= 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 6705febd..48cbef7b 100644
--- a/env_universal.h
+++ b/env_universal.h
@@ -13,6 +13,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
*/
void env_universal_init();
@@ -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 de81f197..6aa42810 100644
--- a/env_universal_common.c
+++ b/env_universal_common.c
@@ -36,11 +36,23 @@
#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 3b53273b..286da9c6 100644
--- a/env_universal_common.h
+++ b/env_universal_common.h
@@ -8,11 +8,23 @@
#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,6 +39,7 @@
enum
{
SET,
+ SET_EXPORT,
ERASE,
BARRIER,
BARRIER_REPLY,
@@ -34,11 +47,6 @@ enum
;
/**
- The table of universal variables
-*/
-extern hash_table_t env_universal_var;
-
-/**
This struct represents a connection between a universal variable server/client
*/
typedef struct connection
@@ -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 08f4f83d..c280aba0 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 30e93b8b..2cf4e599 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 57e860ab..183d0932 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 42bb4cea..6189461f 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 07731251..3acfa515 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 14b389a9..c2a30761 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 bfaaf809..2dbb0c1a 100644
--- a/key_reader.c
+++ b/key_reader.c
@@ -12,17 +12,7 @@
#include <unistd.h>
#include <termcap.h>
-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 4925f168..6a8fa932 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 53512fe6..86b23a0b 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 )