2005-09-20 23:26:39 +10:00
/** \file builtin_set.c Functions defining the set builtin
2012-11-18 11:23:22 +01:00
Functions used for implementing the set builtin .
2005-09-20 23:26:39 +10:00
*/
2006-08-11 11:18:35 +10:00
# include "config.h"
2005-09-20 23:26:39 +10:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <wctype.h>
# include <sys/types.h>
# include <termios.h>
# include <signal.h>
2012-01-10 01:19:37 +05:30
# include <vector>
# include <algorithm>
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-09-20 23:26:39 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2006-01-21 00:27:21 +10:00
# include "wutil.h"
2005-09-20 23:26:39 +10:00
# include "builtin.h"
# include "env.h"
# include "expand.h"
# include "common.h"
# include "wgetopt.h"
# include "proc.h"
# include "parser.h"
2006-07-20 08:55:49 +10:00
2012-02-22 10:51:06 -08:00
/* We know about these buffers */
extern wcstring stdout_buffer , stderr_buffer ;
2005-09-20 23:26:39 +10:00
2006-05-19 18:58:13 +10:00
/**
Error message for invalid path operations
*/
2012-07-07 23:04:02 -07:00
# define BUILTIN_SET_PATH_ERROR L"%ls: Warning: path component %ls may not be valid in %ls.\n"
2006-05-19 18:58:13 +10:00
/**
Hint for invalid path operation with a colon
*/
2006-04-21 04:29:44 +10:00
# define BUILTIN_SET_PATH_HINT L"%ls: Did you mean 'set %ls $%ls %ls'?\n"
2006-05-19 18:58:13 +10:00
/**
Error for mismatch between index count and elements
*/
2006-05-10 02:40:55 +10:00
# define BUILTIN_SET_ARG_COUNT L"%ls: The number of variable indexes does not match the number of values\n"
2006-05-19 18:58:13 +10:00
/**
Test if the specified variable should be subject to path validation
*/
2012-11-18 16:30:30 -08:00
static int is_path_variable ( const wchar_t * env )
2006-05-10 02:40:55 +10:00
{
2012-11-18 16:30:30 -08:00
return contains ( env , L " PATH " , L " CDPATH " ) ;
2006-05-10 02:40:55 +10:00
}
2006-04-21 04:29:44 +10:00
2006-04-19 22:43:15 +10:00
/**
2006-05-10 02:40:55 +10:00
Call env_set . If this is a path variable , e . g . PATH , validate the
elements . On error , print a description of the problem to stderr .
2006-04-19 22:43:15 +10:00
*/
2012-11-18 16:30:30 -08:00
static int my_env_set ( const wchar_t * key , const wcstring_list_t & val , int scope )
2012-01-10 01:19:37 +05:30
{
2012-07-07 23:04:02 -07:00
size_t i ;
int retcode = 0 ;
const wchar_t * val_str = NULL ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( is_path_variable ( key ) )
2012-07-07 23:04:02 -07:00
{
/* Fix for https://github.com/fish-shell/fish-shell/issues/199 . Return success if any path setting succeeds. */
2013-01-30 02:22:38 -08:00
bool any_success = false ;
2012-11-18 11:23:22 +01:00
2013-02-19 17:48:51 -08:00
/* Don't bother validating (or complaining about) values that are already present */
wcstring_list_t existing_values ;
2014-07-12 14:40:46 -07:00
const env_var_t existing_variable = env_get_string ( key , scope ) ;
2013-02-19 17:48:51 -08:00
if ( ! existing_variable . missing_or_empty ( ) )
tokenize_variable_array ( existing_variable , existing_values ) ;
2012-11-18 16:30:30 -08:00
for ( i = 0 ; i < val . size ( ) ; i + + )
2012-07-07 23:04:02 -07:00
{
2013-02-19 17:48:51 -08:00
const wcstring & dir = val . at ( i ) ;
if ( list_contains_string ( existing_values , dir ) )
{
any_success = true ;
continue ;
}
2012-07-07 23:04:02 -07:00
bool show_perror = false ;
int show_hint = 0 ;
bool error = false ;
2012-11-18 11:23:22 +01:00
2012-07-07 23:04:02 -07:00
struct stat buff ;
2012-11-18 16:30:30 -08:00
if ( wstat ( dir , & buff ) )
2012-07-07 23:04:02 -07:00
{
error = true ;
show_perror = true ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! ( S_ISDIR ( buff . st_mode ) ) )
2012-07-07 23:04:02 -07:00
{
error = true ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! error )
2012-07-07 23:04:02 -07:00
{
any_success = true ;
}
else
{
2013-02-19 17:48:51 -08:00
append_format ( stderr_buffer , _ ( BUILTIN_SET_PATH_ERROR ) , L " set " , dir . c_str ( ) , key ) ;
const wchar_t * colon = wcschr ( dir . c_str ( ) , L ' : ' ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( colon & & * ( colon + 1 ) )
2012-07-07 23:04:02 -07:00
{
show_hint = 1 ;
}
2012-11-18 11:23:22 +01:00
2012-07-07 23:04:02 -07:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( show_perror )
2012-07-07 23:04:02 -07:00
{
2012-11-18 16:30:30 -08:00
builtin_wperror ( L " set " ) ;
2012-07-07 23:04:02 -07:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( show_hint )
2012-07-07 23:04:02 -07:00
{
2013-02-19 17:48:51 -08:00
append_format ( stderr_buffer , _ ( BUILTIN_SET_PATH_HINT ) , L " set " , key , key , wcschr ( dir . c_str ( ) , L ' : ' ) + 1 ) ;
2012-07-07 23:04:02 -07:00
}
2012-11-18 11:23:22 +01:00
2012-07-07 23:04:02 -07:00
}
2012-11-18 11:23:22 +01:00
2012-07-07 23:04:02 -07:00
/* Fail at setting the path if we tried to set it to something non-empty, but it wound up empty. */
2012-11-18 16:30:30 -08:00
if ( ! val . empty ( ) & & ! any_success )
2012-07-07 23:04:02 -07:00
{
return 1 ;
}
2012-11-18 11:23:22 +01:00
2012-07-07 23:04:02 -07:00
}
2012-11-18 11:23:22 +01:00
2012-07-07 23:04:02 -07:00
wcstring sb ;
2013-02-16 00:02:40 -08:00
if ( ! val . empty ( ) )
2012-07-07 23:04:02 -07:00
{
2012-11-18 16:30:30 -08:00
for ( i = 0 ; i < val . size ( ) ; i + + )
2012-07-07 23:04:02 -07:00
{
2012-02-22 12:00:02 -08:00
sb . append ( val [ i ] ) ;
2012-11-18 16:30:30 -08:00
if ( i < val . size ( ) - 1 )
2012-07-07 23:04:02 -07:00
{
2012-11-18 16:30:30 -08:00
sb . append ( ARRAY_SEP_STR ) ;
2012-07-07 23:04:02 -07:00
}
}
val_str = sb . c_str ( ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
switch ( env_set ( key , val_str , scope | ENV_USER ) )
2012-07-07 23:04:02 -07:00
{
2012-11-19 00:31:03 -08:00
case ENV_PERM :
{
append_format ( stderr_buffer , _ ( L " %ls: Tried to change the read-only variable '%ls' \n " ) , L " set " , key ) ;
retcode = 1 ;
break ;
}
2012-11-18 11:23:22 +01:00
2014-07-12 14:05:42 -07:00
case ENV_SCOPE :
{
append_format ( stderr_buffer , _ ( L " %ls: Tried to set the special variable '%ls' with the wrong scope \n " ) , L " set " , key ) ;
retcode = 1 ;
break ;
}
2012-11-19 00:31:03 -08:00
case ENV_INVALID :
{
2014-07-13 19:08:15 -07:00
append_format ( stderr_buffer , _ ( L " %ls: Tried to set the special variable '%ls' to an invalid value \n " ) , L " set " , key ) ;
2012-11-19 00:31:03 -08:00
retcode = 1 ;
break ;
}
2012-07-07 23:04:02 -07:00
}
2012-11-18 11:23:22 +01:00
2012-07-07 23:04:02 -07:00
return retcode ;
2012-01-10 01:19:37 +05:30
}
2012-11-18 11:23:22 +01:00
/**
Extract indexes from a destination argument of the form name [ index1 index2 . . . ]
2006-05-10 02:40:55 +10:00
2012-11-18 11:23:22 +01:00
\ param indexes the list to insert the new indexes into
\ param src the source string to parse
\ param name the name of the element . Return null if the name in \ c src does not match this name
\ param var_count the number of elements in the array to parse .
2006-05-10 02:40:55 +10:00
2012-11-18 11:23:22 +01:00
\ return the total number of indexes parsed , or - 1 on error
2005-09-20 23:26:39 +10:00
*/
2012-11-18 16:30:30 -08:00
static int parse_index ( std : : vector < long > & indexes ,
const wchar_t * src ,
const wchar_t * name ,
size_t var_count )
2012-01-10 01:19:37 +05:30
{
2012-11-18 16:30:30 -08:00
size_t len ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
int count = 0 ;
const wchar_t * src_orig = src ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( src = = 0 )
{
return 0 ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
while ( * src ! = L ' \0 ' & & ( iswalnum ( * src ) | | * src = = L ' _ ' ) )
{
src + + ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( * src ! = L ' [ ' )
{
append_format ( stderr_buffer , _ ( BUILTIN_SET_ARG_COUNT ) , L " set " ) ;
return 0 ;
}
len = src - src_orig ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ( wcsncmp ( src_orig , name , len ) ! = 0 ) | | ( wcslen ( name ) ! = ( len ) ) )
{
append_format ( stderr_buffer ,
_ ( L " %ls: Multiple variable names specified in single call (%ls and %.*ls) \n " ) ,
L " set " ,
name ,
len ,
src_orig ) ;
return 0 ;
}
2012-11-18 11:23:22 +01:00
src + + ;
2012-11-18 16:30:30 -08:00
while ( iswspace ( * src ) )
{
src + + ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
while ( * src ! = L ' ] ' )
{
wchar_t * end ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
long l_ind ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
errno = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
l_ind = wcstol ( src , & end , 10 ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( end = = src | | errno )
{
append_format ( stderr_buffer , _ ( L " %ls: Invalid index starting at '%ls' \n " ) , L " set " , src ) ;
return 0 ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( l_ind < 0 )
{
l_ind = var_count + l_ind + 1 ;
}
src = end ;
if ( * src = = L ' . ' & & * ( src + 1 ) = = L ' . ' )
{
src + = 2 ;
long l_ind2 = wcstol ( src , & end , 10 ) ;
if ( end = = src | | errno )
{
return 1 ;
}
src = end ;
if ( l_ind2 < 0 )
{
l_ind2 = var_count + l_ind2 + 1 ;
}
int direction = l_ind2 < l_ind ? - 1 : 1 ;
for ( long jjj = l_ind ; jjj * direction < = l_ind2 * direction ; jjj + = direction )
{
// debug(0, L"Expand range [set]: %i\n", jjj);
indexes . push_back ( jjj ) ;
count + + ;
}
}
else
{
indexes . push_back ( l_ind ) ;
count + + ;
}
while ( iswspace ( * src ) ) src + + ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
return count ;
2012-01-10 01:19:37 +05:30
}
2012-11-18 16:30:30 -08:00
static int update_values ( wcstring_list_t & list ,
std : : vector < long > & indexes ,
wcstring_list_t & values )
2012-01-10 01:19:37 +05:30
{
2012-11-18 16:30:30 -08:00
size_t i ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/* Replace values where needed */
for ( i = 0 ; i < indexes . size ( ) ; i + + )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
/*
The ' - 1 ' below is because the indices in fish are
one - based , but the vector uses zero - based indices
*/
long ind = indexes [ i ] - 1 ;
const wcstring newv = values [ i ] ;
if ( ind < 0 )
{
return 1 ;
}
if ( ( size_t ) ind > = list . size ( ) )
2012-06-21 10:24:49 -07:00
{
2012-11-18 16:30:30 -08:00
list . resize ( ind + 1 ) ;
2012-06-21 10:24:49 -07:00
}
2012-11-18 11:23:22 +01:00
// free((void *) al_get(list, ind));
2012-11-18 16:30:30 -08:00
list [ ind ] = newv ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
return 0 ;
2012-01-10 01:19:37 +05:30
}
2005-09-20 23:26:39 +10:00
2012-01-10 01:19:37 +05:30
/**
2012-11-18 11:23:22 +01:00
Erase from a list of wcstring values at specified indexes
2012-01-10 01:19:37 +05:30
*/
2012-11-18 11:23:22 +01:00
static void erase_values ( wcstring_list_t & list , const std : : vector < long > & indexes )
2012-01-10 01:19:37 +05:30
{
2012-05-10 01:04:18 -07:00
// Make a set of indexes.
// This both sorts them into ascending order and removes duplicates.
const std : : set < long > indexes_set ( indexes . begin ( ) , indexes . end ( ) ) ;
2012-11-18 11:23:22 +01:00
2012-05-10 01:04:18 -07:00
// Now walk the set backwards, so we encounter larger indexes first, and remove elements at the given (1-based) indexes.
std : : set < long > : : const_reverse_iterator iter ;
2013-02-16 00:02:40 -08:00
for ( iter = indexes_set . rbegin ( ) ; iter ! = indexes_set . rend ( ) ; + + iter )
2012-11-18 16:30:30 -08:00
{
2012-05-10 01:04:18 -07:00
long val = * iter ;
2012-11-18 16:30:30 -08:00
if ( val > 0 & & ( size_t ) val < = list . size ( ) )
{
2012-05-10 01:04:18 -07:00
// One-based indexing!
list . erase ( list . begin ( ) + val - 1 ) ;
}
}
2012-01-10 01:19:37 +05:30
}
2005-09-20 23:26:39 +10:00
/**
2012-03-19 11:52:18 -07:00
Print the names of all environment variables in the scope , with or without shortening ,
with or without values , with or without escaping
2005-09-20 23:26:39 +10:00
*/
2012-11-18 11:23:22 +01:00
static void print_variables ( int include_values , int esc , bool shorten_ok , int scope )
2005-09-20 23:26:39 +10:00
{
2012-02-03 18:39:41 -08:00
wcstring_list_t names = env_get_names ( scope ) ;
sort ( names . begin ( ) , names . end ( ) ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
for ( size_t i = 0 ; i < names . size ( ) ; i + + )
{
const wcstring key = names . at ( i ) ;
2012-02-03 18:39:41 -08:00
const wcstring e_key = escape_string ( key , 0 ) ;
2005-10-07 20:36:51 +10:00
2012-11-18 16:30:30 -08:00
stdout_buffer . append ( e_key ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( include_values )
2012-11-18 11:23:22 +01:00
{
2014-07-12 14:40:46 -07:00
env_var_t value = env_get_string ( key , scope ) ;
2012-11-18 16:30:30 -08:00
if ( ! value . missing ( ) )
{
int shorten = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( shorten_ok & & value . length ( ) > 64 )
{
shorten = 1 ;
value . resize ( 60 ) ;
}
wcstring e_value = esc ? expand_escape_variable ( value ) : value ;
2012-11-18 11:23:22 +01:00
2012-02-22 10:51:06 -08:00
stdout_buffer . append ( L " " ) ;
stdout_buffer . append ( e_value ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( shorten )
{
2013-04-19 10:20:47 -07:00
stdout_buffer . push_back ( ellipsis_char ) ;
2012-11-18 16:30:30 -08:00
}
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
stdout_buffer . append ( L " \n " ) ;
2012-11-18 11:23:22 +01:00
}
2005-09-20 23:26:39 +10:00
}
2006-04-21 04:29:44 +10:00
2005-09-20 23:26:39 +10:00
/**
2006-05-19 18:58:13 +10:00
The set builtin . Creates , updates and erases environment variables
and environemnt variable arrays .
2005-09-20 23:26:39 +10:00
*/
2012-11-18 16:30:30 -08:00
static int builtin_set ( parser_t & parser , wchar_t * * argv )
2005-09-20 23:26:39 +10:00
{
2013-01-31 15:57:08 -08:00
/** Variables used for parsing the argument list */
const struct woption long_options [ ] =
2012-11-18 11:23:22 +01:00
{
2013-01-31 15:57:08 -08:00
{ L " export " , no_argument , 0 , ' x ' } ,
{ L " global " , no_argument , 0 , ' g ' } ,
{ L " local " , no_argument , 0 , ' l ' } ,
{ L " erase " , no_argument , 0 , ' e ' } ,
{ L " names " , no_argument , 0 , ' n ' } ,
{ L " unexport " , no_argument , 0 , ' u ' } ,
{ L " universal " , no_argument , 0 , ' U ' } ,
{ L " long " , no_argument , 0 , ' L ' } ,
{ L " query " , no_argument , 0 , ' q ' } ,
{ L " help " , no_argument , 0 , ' h ' } ,
{ 0 , 0 , 0 , 0 }
} ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
const wchar_t * short_options = L " +xglenuULqh " ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
int argc = builtin_count_args ( argv ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/*
Flags to set the work mode
*/
int local = 0 , global = 0 , exportv = 0 ;
int erase = 0 , list = 0 , unexport = 0 ;
int universal = 0 , query = 0 ;
bool shorten_ok = true ;
2013-01-31 15:57:08 -08:00
bool preserve_incoming_failure_exit_status = true ;
const int incoming_exit_status = proc_get_last_status ( ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/*
Variables used for performing the actual work
*/
wchar_t * dest = 0 ;
int retcode = 0 ;
int scope ;
int slice = 0 ;
int i ;
2012-11-18 11:23:22 +01:00
2014-06-09 12:57:44 -07:00
const wchar_t * bad_char = NULL ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/* Parse options to obtain the requested operation and the modifiers */
woptind = 0 ;
while ( 1 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
int c = wgetopt_long ( argc , argv , short_options , long_options , 0 ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( c = = - 1 )
{
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
switch ( c )
{
2012-11-19 00:31:03 -08:00
case 0 :
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' e ' :
erase = 1 ;
2013-01-31 15:57:08 -08:00
preserve_incoming_failure_exit_status = false ;
2012-11-19 00:31:03 -08:00
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' n ' :
list = 1 ;
2013-01-31 15:57:08 -08:00
preserve_incoming_failure_exit_status = false ;
2012-11-19 00:31:03 -08:00
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' x ' :
exportv = 1 ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' l ' :
local = 1 ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' g ' :
global = 1 ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' u ' :
unexport = 1 ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' U ' :
universal = 1 ;
break ;
2006-05-26 21:24:02 +10:00
2012-11-19 00:31:03 -08:00
case ' L ' :
shorten_ok = false ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' q ' :
query = 1 ;
2013-01-31 15:57:08 -08:00
preserve_incoming_failure_exit_status = false ;
2012-11-19 00:31:03 -08:00
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' h ' :
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
return 0 ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' ? ' :
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
return 1 ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
default :
break ;
2012-11-18 16:30:30 -08:00
}
}
/*
Ok , all arguments have been parsed , let ' s validate them
*/
/*
If we are checking the existance of a variable ( - q ) we can not
also specify scope
*/
if ( query & & ( erase | | list ) )
{
append_format ( stderr_buffer ,
BUILTIN_ERR_COMBO ,
argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2012-11-18 11:23:22 +01:00
return 1 ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
2014-07-12 00:21:04 -07:00
/* We can't both list and erase variables */
2012-11-18 16:30:30 -08:00
if ( erase & & list )
{
append_format ( stderr_buffer ,
BUILTIN_ERR_COMBO ,
argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
return 1 ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
2012-11-18 11:23:22 +01:00
/*
2012-11-18 16:30:30 -08:00
Variables can only have one scope
2012-11-18 11:23:22 +01:00
*/
2012-11-18 16:30:30 -08:00
if ( local + global + universal > 1 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
append_format ( stderr_buffer ,
BUILTIN_ERR_GLOCAL ,
argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
return 1 ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/*
Variables can only have one export status
*/
if ( exportv & & unexport )
{
append_format ( stderr_buffer ,
BUILTIN_ERR_EXPUNEXP ,
argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
return 1 ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/*
Calculate the scope value for variable assignement
*/
scope = ( local ? ENV_LOCAL : 0 ) | ( global ? ENV_GLOBAL : 0 ) | ( exportv ? ENV_EXPORT : 0 ) | ( unexport ? ENV_UNEXPORT : 0 ) | ( universal ? ENV_UNIVERSAL : 0 ) | ENV_USER ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( query )
{
/*
Query mode . Return the number of variables that do not exist
out of the specified variables .
*/
int i ;
for ( i = woptind ; i < argc ; i + + )
{
wchar_t * arg = argv [ i ] ;
int slice = 0 ;
if ( ! ( dest = wcsdup ( arg ) ) )
{
DIE_MEM ( ) ;
}
if ( wcschr ( dest , L ' [ ' ) )
{
slice = 1 ;
* wcschr ( dest , L ' [ ' ) = 0 ;
}
if ( slice )
{
std : : vector < long > indexes ;
wcstring_list_t result ;
size_t j ;
2012-11-18 11:23:22 +01:00
2014-07-12 14:40:46 -07:00
env_var_t dest_str = env_get_string ( dest , scope ) ;
2012-01-14 02:42:17 -08:00
if ( ! dest_str . missing ( ) )
2012-11-18 16:30:30 -08:00
tokenize_variable_array ( dest_str , result ) ;
if ( ! parse_index ( indexes , arg , dest , result . size ( ) ) )
{
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
retcode = 1 ;
break ;
}
for ( j = 0 ; j < indexes . size ( ) ; j + + )
{
long idx = indexes [ j ] ;
if ( idx < 1 | | ( size_t ) idx > result . size ( ) )
{
retcode + + ;
}
}
}
else
{
if ( ! env_exist ( arg , scope ) )
{
retcode + + ;
}
}
free ( dest ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
return retcode ;
}
if ( list )
{
/* Maybe we should issue an error if there are any other arguments? */
print_variables ( 0 , 0 , shorten_ok , scope ) ;
return 0 ;
}
if ( woptind = = argc )
{
/*
Print values of variables
*/
if ( erase )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
append_format ( stderr_buffer ,
_ ( L " %ls: Erase needs a variable name \n " ) ,
argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
retcode = 1 ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
else
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
print_variables ( 1 , 1 , shorten_ok , scope ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
return retcode ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( ! ( dest = wcsdup ( argv [ woptind ] ) ) )
{
DIE_MEM ( ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( wcschr ( dest , L ' [ ' ) )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
slice = 1 ;
* wcschr ( dest , L ' [ ' ) = 0 ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! wcslen ( dest ) )
{
free ( dest ) ;
append_format ( stderr_buffer , BUILTIN_ERR_VARNAME_ZERO , argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
return 1 ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( ( bad_char = wcsvarname ( dest ) ) )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
append_format ( stderr_buffer , BUILTIN_ERR_VARCHAR , argv [ 0 ] , * bad_char ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
free ( dest ) ;
return 1 ;
2012-11-18 11:23:22 +01:00
}
/*
2012-11-18 16:30:30 -08:00
set assignment can work in two modes , either using slices or
using the whole array . We detect which mode is used here .
2012-11-18 11:23:22 +01:00
*/
2012-11-18 16:30:30 -08:00
if ( slice )
{
/*
Slice mode
*/
std : : vector < long > indexes ;
wcstring_list_t result ;
2012-11-18 11:23:22 +01:00
2014-07-12 14:40:46 -07:00
const env_var_t dest_str = env_get_string ( dest , scope ) ;
2012-01-14 02:42:17 -08:00
if ( ! dest_str . missing ( ) )
2014-07-12 15:43:32 -07:00
{
2012-11-18 16:30:30 -08:00
tokenize_variable_array ( dest_str , result ) ;
2014-07-12 15:43:32 -07:00
}
else if ( erase )
2012-11-18 16:30:30 -08:00
{
2014-07-12 15:43:32 -07:00
retcode = 1 ;
}
2012-11-18 11:23:22 +01:00
2014-07-12 15:43:32 -07:00
if ( ! retcode )
{
for ( ; woptind < argc ; woptind + + )
2012-11-18 16:30:30 -08:00
{
2014-07-12 15:43:32 -07:00
if ( ! parse_index ( indexes , argv [ woptind ] , dest , result . size ( ) ) )
2012-11-18 16:30:30 -08:00
{
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2014-07-12 15:43:32 -07:00
retcode = 1 ;
2012-11-18 16:30:30 -08:00
break ;
}
2014-07-12 15:43:32 -07:00
size_t idx_count = indexes . size ( ) ;
size_t val_count = argc - woptind - 1 ;
if ( ! erase )
2012-11-18 16:30:30 -08:00
{
2014-07-12 15:43:32 -07:00
if ( val_count < idx_count )
{
append_format ( stderr_buffer , _ ( BUILTIN_SET_ARG_COUNT ) , argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
retcode = 1 ;
break ;
}
if ( val_count = = idx_count )
{
woptind + + ;
break ;
}
2012-11-18 16:30:30 -08:00
}
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( ! retcode )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
/*
Slice indexes have been calculated , do the actual work
*/
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( erase )
{
erase_values ( result , indexes ) ;
my_env_set ( dest , result , scope ) ;
}
else
{
wcstring_list_t value ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
while ( woptind < argc )
{
value . push_back ( argv [ woptind + + ] ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( update_values ( result ,
indexes ,
value ) )
{
append_format ( stderr_buffer , L " %ls: " , argv [ 0 ] ) ;
append_format ( stderr_buffer , ARRAY_BOUNDS_ERR ) ;
stderr_buffer . push_back ( L ' \n ' ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
my_env_set ( dest , result , scope ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
}
2012-11-18 11:23:22 +01:00
}
else
{
2012-11-18 16:30:30 -08:00
woptind + + ;
/*
No slicing
*/
if ( erase )
{
if ( woptind ! = argc )
{
append_format ( stderr_buffer ,
_ ( L " %ls: Values cannot be specfied with erase \n " ) ,
argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
retcode = 1 ;
}
else
{
retcode = env_remove ( dest , scope ) ;
}
}
else
{
2012-02-07 23:53:34 -08:00
wcstring_list_t val ;
2012-11-18 16:30:30 -08:00
for ( i = woptind ; i < argc ; i + + )
2012-02-07 23:53:34 -08:00
val . push_back ( argv [ i ] ) ;
2012-11-18 16:30:30 -08:00
retcode = my_env_set ( dest , val , scope ) ;
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
free ( dest ) ;
2012-11-18 11:23:22 +01:00
2013-01-31 15:57:08 -08:00
if ( retcode = = STATUS_BUILTIN_OK & & preserve_incoming_failure_exit_status )
retcode = incoming_exit_status ;
2012-11-18 16:30:30 -08:00
return retcode ;
2006-05-10 02:40:55 +10:00
2005-09-20 23:26:39 +10:00
}