Make it possible to specify scope of a variable to be erased or tested. Also make sure set exits with a non-zero exit status when erasing fails.

darcs-hash:20060604201451-ac50b-4ea0212c513b33be40559dfe8d65c1446c53f682.gz
This commit is contained in:
axel 2006-06-05 06:14:51 +10:00
parent cf35a8e3a5
commit 04b142208d
8 changed files with 162 additions and 79 deletions

View file

@ -256,8 +256,7 @@ static int parse_index( array_list_t *indexes,
indexes. The previous entries at the specidied position will be
free'd.
\return The number of elements in the list after the modifications
have been made
\return 0 if the operation was successfull, non-zero otherwise
*/
static int update_values( array_list_t *list,
array_list_t *indexes,
@ -270,11 +269,16 @@ static int update_values( array_list_t *list,
{
int ind = *(int *) al_get(indexes, i) - 1;
void *new = (void *) al_get(values, i);
if( ind <= 0 )
{
return 1;
}
free((void *) al_get(list, ind));
al_set(list, ind, new != 0 ? wcsdup(new) : wcsdup(L""));
}
return al_get_count(list);
return 0;
}
@ -571,13 +575,13 @@ int builtin_set( wchar_t **argv )
if( query )
{
/*
Query mode. Return the number variables that do not exist
Query mode. Return the number of variables that do not exist
out of the specified variables.
*/
int i;
for( i=woptind; i<argc; i++ )
{
if( !env_exist( argv[i] ) )
if( !env_exist( argv[i], scope ) )
{
retcode++;
}
@ -616,7 +620,7 @@ int builtin_set( wchar_t **argv )
print_variables(0, 0, scope);
return 0;
}
if( !(dest = wcsdup(argv[woptind])))
{
die_mem();
@ -636,6 +640,13 @@ int builtin_set( wchar_t **argv )
return 1;
}
if( slice && erase && (scope != ENV_USER) )
{
free( dest );
sb_printf( sb_err, _(L"%ls: Can not specify scope when erasing array slice\n"), argv[0] );
builtin_print_help( argv[0], sb_err );
return 1;
}
/*
set assignment can work in two modes, either using slices or
@ -709,9 +720,14 @@ int builtin_set( wchar_t **argv )
al_push(&value, argv[woptind++]);
}
update_values( &result,
&indexes,
&value );
if( update_values( &result,
&indexes,
&value ) )
{
sb_printf( sb_err, L"%ls: ", argv[0] );
sb_printf( sb_err, ARRAY_BOUNDS_ERR );
sb_append( sb_err, L"\n" );
}
my_env_set(dest,
&result,
@ -750,7 +766,7 @@ int builtin_set( wchar_t **argv )
}
else
{
env_remove( dest, ENV_USER );
retcode = env_remove( dest, scope );
}
}
else

View file

@ -1,11 +1,12 @@
\section set set - Handle environment variables.
\subsection set-synopsis Synopsis
<pre>set [OPTIONS] [VARIABLE_NAME [VALUES...]]
set [OPTIONS] [VARIABLE_NAME[INDICES]... [VALUES...]]
set -q VARIABLE_NAMES...
set (-e | --erase) VARIABLE_NAME[INDICES]...
set (-e | --erase) VARIABLE_NAME</pre>
<pre>set [SCOPE_OPTIONS]
set [OPTIONS] VARIABLE_NAME VALUES...
set [OPTIONS] VARIABLE_NAME[INDICES]... VALUES...
set (-q | --query) [SCOPE_OPTIONS] VARIABLE_NAMES...
set (-e | --erase) [SCOPE_OPTIONS] VARIABLE_NAME
set (-e | --erase) [SCOPE_OPTIONS] VARIABLE_NAME[INDICES]... </pre>
The <code>set</code> builtin causes fish to assign the variable <code>VARIABLE_NAME</code> the values <code>VALUES...</code>.
@ -37,8 +38,6 @@ expanding or assigning to an array variable, the index will be
calculated from the end of the array. For example, the index -1 means
the last index of an array.
-# If a variable is explicitly set to either universal, global or local, that setting will be honored. If a variable of the same name exists in a different scope, that variable will not be changed.
-# If a variable is not explicitly set to be either universal, global or local, but has been previously defined, the previos variable scope is used.
-# If a variable is not explicitly set to be either universal, global or local and has never before been defined, the variable will be local to the currently executing functions. If no function is executing, the variable will be global.
@ -47,20 +46,27 @@ the last index of an array.
-# If a variable is not explicitly set to be exported or not exported, but has been previously defined, the previous exporting rule for the variable is kept.
-# If a variable is not explicitly set to be either global or local and has never before been defined, the variable will not be exported.
If the \c -e or \c --erase option is specified, the variable specified
by the following arguments will be erased. If variable indices are
specified, only the thecified slices of the array veraible will be
erased.
In query mode, the scope to be examined can be specified.
In erase mode, if variable indices are specified, only the specified
slices of the array variable will be erased. When erasing an entire
variable (i.e. no slicing), the scope of the variable to be erased can
be specified. That way, a global variable can be erased even if a
local variable with the same name exists. Scope can not be specified
when erasing a slice of an array. The innermost scope is always used.
The set command requires all switch arguments to come before any
non-switch arguments. For example, <code>set flags -l</code> will have
the effect of setting the value of the variable <code>flags</code> to
'-l', not making the variable local.
Set exits with an exit status of zero it the variable assignemnts
where sucessfully performed, with a non-zero exit status otherwise. In
query mode, the exit status is the number of variables that where not
found.
In assignment mode, set exits with an exit status of zero it the
variable assignments where sucessfully performed, with a non-zero exit
status otherwise. In query mode, the exit status is the number of
variables that where not found. In erase mode, set exits with a zero
exit status in case of success, with a non-zero exit status if the
commandline was invalid, if the variable was readprotected or if the
variable did not exist.
\subsection set-example Example

140
env.c
View file

@ -822,10 +822,12 @@ int env_set( const wchar_t *key,
\return zero if the variable was not found, non-zero otherwise
*/
static int try_remove( env_node_t *n,
const wchar_t *key )
const wchar_t *key,
int var_mode )
{
const void *old_key_void, *old_val_void;
wchar_t *old_key, *old_val;
if( n == 0 )
return 0;
@ -850,44 +852,70 @@ static int try_remove( env_node_t *n,
return 1;
}
if( var_mode & ENV_LOCAL )
return 0;
if( n->new_scope )
return try_remove( global_env, key );
return try_remove( global_env, key, var_mode );
else
return try_remove( n->next, key );
return try_remove( n->next, key, var_mode );
}
void env_remove( const wchar_t *key, int var_mode )
int env_remove( const wchar_t *key, int var_mode )
{
env_node_t *first_node;
int erased = 0;
if( (var_mode & ENV_USER ) &&
hash_get( &env_read_only, key ) )
{
return;
return 2;
}
if( try_remove( top, key ) )
{
event_t ev;
ev.type=EVENT_VARIABLE;
ev.param1.variable=key;
ev.function_name=0;
al_init( &ev.arguments );
al_push( &ev.arguments, L"VARIABLE" );
al_push( &ev.arguments, L"ERASE" );
al_push( &ev.arguments, key );
event_fire( &ev );
al_destroy( &ev.arguments );
}
else
first_node = top;
if( ! (var_mode & ENV_UNIVERSAL ) )
{
env_universal_remove( key );
if( var_mode & ENV_GLOBAL )
{
first_node = global_env;
}
if( try_remove( first_node, key, var_mode ) )
{
event_t ev;
ev.type=EVENT_VARIABLE;
ev.param1.variable=key;
ev.function_name=0;
al_init( &ev.arguments );
al_push( &ev.arguments, L"VARIABLE" );
al_push( &ev.arguments, L"ERASE" );
al_push( &ev.arguments, key );
event_fire( &ev );
al_destroy( &ev.arguments );
erased = 1;
}
}
if( !erased &&
!(var_mode & ENV_GLOBAL) &&
!(var_mode & ENV_LOCAL) )
{
erased = !env_universal_remove( key );
}
if( is_locale( key ) )
{
handle_locale();
}
return !erased;
}
@ -989,40 +1017,60 @@ wchar_t *env_get( const wchar_t *key )
return item;
}
int env_exist( const wchar_t *key )
int env_exist( const wchar_t *key, int mode )
{
var_entry_t *res;
env_node_t *env = top;
wchar_t *item;
if( hash_get( &env_read_only, key ) || hash_get( &env_electric, key ) )
{
return 1;
}
while( env != 0 )
env_node_t *env;
wchar_t *item=0;
/*
Read only variables all exist, and they are all global. A local
varion can not exist.
*/
if( ! (mode & ENV_LOCAL) && ! (mode & ENV_UNIVERSAL) )
{
res = (var_entry_t *) hash_get( &env->env,
key );
if( res != 0 )
if( hash_get( &env_read_only, key ) || hash_get( &env_electric, key ) )
{
return 1;
}
if( env->new_scope )
env = global_env;
else
env = env->next;
}
if( !proc_had_barrier)
}
if( ! (mode & ENV_UNIVERSAL) )
{
proc_had_barrier=1;
env_universal_barrier();
env = (mode & ENV_GLOBAL)?global_env:top;
while( env != 0 )
{
res = (var_entry_t *) hash_get( &env->env,
key );
if( res != 0 )
{
return 1;
}
if( mode & ENV_LOCAL )
break;
if( env->new_scope )
env = global_env;
else
env = env->next;
}
}
item = env_universal_get( key );
if( ! (mode & ENV_LOCAL) && ! (mode & ENV_GLOBAL) )
{
if( !proc_had_barrier)
{
proc_had_barrier=1;
env_universal_barrier();
}
item = env_universal_get( key );
}
return item != 0;
}
/**

11
env.h
View file

@ -91,16 +91,21 @@ wchar_t *env_get( const wchar_t *key );
/**
Returns 1 if the specified key exists. This can't be reliable done
using env_get, since env_get returns null for 0-element arrays
\param key The name of the variable to remove
\param mode the scope to search in. All scopes are searched if unset
*/
int env_exist( const wchar_t *key );
int env_exist( const wchar_t *key, int mode );
/**
Remove environemnt variable
\param key The name of the variable to remove
\param mode should be ENV_USER if this is a remove request from the user, 0 otherwise. If this is a user request, read-only variables can not be removed.
\param mode should be ENV_USER if this is a remove request from the user, 0 otherwise. If this is a user request, read-only variables can not be removed. The mode may also specify the scope of the variable that should be erased.
\return zero if the variable existed, and non-zero if the variable did not exist
*/
void env_remove( const wchar_t *key, int mode );
int env_remove( const wchar_t *key, int mode );
/**
Push the variable stack. Used for implementing local variables for functions and for-loops.

View file

@ -395,11 +395,15 @@ void env_universal_set( const wchar_t *name, const wchar_t *value, int export )
env_universal_barrier();
}
void env_universal_remove( const wchar_t *name )
int env_universal_remove( const wchar_t *name )
{
int res;
message_t *msg;
if( !init )
return;
return 1;
res = !env_universal_common_get( name );
debug( 3,
L"env_universal_remove( \"%ls\" )",
@ -409,6 +413,8 @@ void env_universal_remove( const wchar_t *name )
msg->count=1;
q_put( &env_universal_server.unsent, msg );
env_universal_barrier();
return res;
}
void env_universal_get_names( array_list_t *l,

View file

@ -40,8 +40,10 @@ int env_universal_get_export( const wchar_t *name );
void env_universal_set( const wchar_t *name, const wchar_t *val, int export );
/**
Erase a universal variable
\return zero if the variable existed, and non-zero if the variable did not exist
*/
void env_universal_remove( const wchar_t *name );
int env_universal_remove( const wchar_t *name );
/**
Read all available messages from the server.

View file

@ -824,7 +824,7 @@ static int expand_variables( wchar_t *in, array_list_t *out, int last_idx )
{
error( SYNTAX_ERROR,
-1,
L"Array index out of bounds" );
ARRAY_BOUNDS_ERR );
is_ok=0;
al_truncate( var_idx_list, j );
break;

View file

@ -132,7 +132,7 @@ enum
*/
#define COMPLETE_VAR_PARAN_DESC _( L"Did you mean (COMMAND)? In fish, the '$' character is only used for accessing variables. To learn more about command substitution in fish, type 'help expand-command-substitution'.")
#define ARRAY_BOUNDS_ERR _(L"Array index out of bounds")
/**