2005-09-20 23:26:39 +10:00
/** \file builtin_set.c Functions defining the set builtin
2011-12-26 19:18:46 -08: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
2005-09-20 23:26:39 +10:00
2006-05-19 18:58:13 +10:00
/**
Error message for invalid path operations
*/
2006-04-21 04:29:44 +10:00
# define BUILTIN_SET_PATH_ERROR L"%ls: Could not add component %ls to %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
*/
2006-05-10 02:40:55 +10:00
static int is_path_variable ( const wchar_t * env )
{
2007-09-29 07:32:27 +10:00
return contains ( env ,
2006-05-10 02:40:55 +10:00
L " PATH " ,
2007-09-29 07:32:27 +10:00
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
*/
2006-05-10 02:40:55 +10:00
static int my_env_set ( const wchar_t * key , array_list_t * val , int scope )
2006-04-11 01:36:26 +10:00
{
2006-05-10 02:40:55 +10:00
string_buffer_t sb ;
int i ;
int retcode = 0 ;
wchar_t * val_str = 0 ;
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
if ( is_path_variable ( key ) )
2006-04-11 01:36:26 +10:00
{
2006-05-10 02:40:55 +10:00
int error = 0 ;
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
for ( i = 0 ; i < al_get_count ( val ) ; i + + )
2006-04-11 01:36:26 +10:00
{
2006-05-10 02:40:55 +10:00
int show_perror = 0 ;
int show_hint = 0 ;
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
struct stat buff ;
2012-01-10 01:19:37 +05:30
const wchar_t * dir = ( wchar_t * ) al_get ( val , i ) ;
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
if ( wstat ( dir , & buff ) )
{
error = 1 ;
show_perror = 1 ;
}
2006-08-01 10:24:11 +10:00
if ( ! ( S_ISDIR ( buff . st_mode ) ) )
2006-05-10 02:40:55 +10:00
{
error = 1 ;
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
if ( error )
{
2012-01-10 01:19:37 +05:30
const wchar_t * colon ;
2011-12-26 19:18:46 -08:00
sb_printf ( sb_err ,
2006-05-10 02:40:55 +10:00
_ ( BUILTIN_SET_PATH_ERROR ) ,
2011-12-26 19:18:46 -08:00
L " set " ,
dir ,
2006-05-10 02:40:55 +10:00
key ) ;
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
colon = wcschr ( dir , L ' : ' ) ;
2011-12-26 19:18:46 -08:00
if ( colon & & * ( colon + 1 ) )
2006-05-10 02:40:55 +10:00
{
show_hint = 1 ;
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
if ( show_perror )
{
builtin_wperror ( L " set " ) ;
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
if ( show_hint )
{
2011-12-26 19:18:46 -08:00
sb_printf ( sb_err ,
2006-05-10 02:40:55 +10:00
_ ( BUILTIN_SET_PATH_HINT ) ,
L " set " ,
key ,
key ,
wcschr ( dir , L ' : ' ) + 1 ) ;
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
if ( error )
{
break ;
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
}
if ( error )
{
return 1 ;
2006-04-11 01:36:26 +10:00
}
2011-12-26 19:18:46 -08:00
2006-04-11 01:36:26 +10:00
}
2006-05-10 02:40:55 +10:00
sb_init ( & sb ) ;
2005-09-20 23:26:39 +10:00
2006-05-10 02:40:55 +10:00
if ( al_get_count ( val ) )
2005-09-20 23:26:39 +10:00
{
2006-05-10 02:40:55 +10:00
for ( i = 0 ; i < al_get_count ( val ) ; i + + )
{
2007-01-28 23:43:31 +10:00
wchar_t * next = ( wchar_t * ) al_get ( val , i ) ;
sb_append ( & sb , next ? next : L " " ) ;
2006-05-10 02:40:55 +10:00
if ( i < al_get_count ( val ) - 1 )
{
sb_append ( & sb , ARRAY_SEP_STR ) ;
}
}
val_str = ( wchar_t * ) sb . buff ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
switch ( env_set ( key , val_str , scope | ENV_USER ) )
2005-09-20 23:26:39 +10:00
{
2006-05-10 02:40:55 +10:00
case ENV_PERM :
{
sb_printf ( sb_err , _ ( L " %ls: Tried to change the read-only variable '%ls' \n " ) , L " set " , key ) ;
retcode = 1 ;
break ;
}
2011-12-26 19:18:46 -08:00
2006-06-09 09:52:12 +10:00
case ENV_INVALID :
{
sb_printf ( sb_err , _ ( L " %ls: Unknown error " ) , L " set " ) ;
retcode = 1 ;
break ;
}
2005-09-20 23:26:39 +10:00
}
2006-05-10 02:40:55 +10:00
sb_destroy ( & sb ) ;
2005-09-20 23:26:39 +10:00
2006-05-10 02:40:55 +10:00
return retcode ;
}
2005-09-20 23:26:39 +10:00
2012-01-10 01:19:37 +05:30
static int my_env_set2 ( const wchar_t * key , wcstring_list_t & val , int scope )
{
string_buffer_t sb ;
int i ;
int retcode = 0 ;
wchar_t * val_str = 0 ;
if ( is_path_variable ( key ) )
{
int error = 0 ;
for ( i = 0 ; i < val . size ( ) ; i + + )
{
int show_perror = 0 ;
int show_hint = 0 ;
struct stat buff ;
const wchar_t * dir = val [ i ] . c_str ( ) ;
if ( wstat ( dir , & buff ) )
{
error = 1 ;
show_perror = 1 ;
}
if ( ! ( S_ISDIR ( buff . st_mode ) ) )
{
error = 1 ;
}
if ( error )
{
const wchar_t * colon ;
sb_printf ( sb_err ,
_ ( BUILTIN_SET_PATH_ERROR ) ,
L " set " ,
dir ,
key ) ;
colon = wcschr ( dir , L ' : ' ) ;
if ( colon & & * ( colon + 1 ) )
{
show_hint = 1 ;
}
}
if ( show_perror )
{
builtin_wperror ( L " set " ) ;
}
if ( show_hint )
{
sb_printf ( sb_err ,
_ ( BUILTIN_SET_PATH_HINT ) ,
L " set " ,
key ,
key ,
wcschr ( dir , L ' : ' ) + 1 ) ;
}
if ( error )
{
break ;
}
}
if ( error )
{
return 1 ;
}
}
sb_init ( & sb ) ;
if ( val . size ( ) )
{
for ( i = 0 ; i < val . size ( ) ; i + + )
{
const wchar_t * next = val [ i ] . c_str ( ) ;
sb_append ( & sb , next ? next : L " " ) ;
if ( i < val . size ( ) - 1 )
{
sb_append ( & sb , ARRAY_SEP_STR ) ;
}
}
val_str = ( wchar_t * ) sb . buff ;
}
switch ( env_set ( key , val_str , scope | ENV_USER ) )
{
case ENV_PERM :
{
sb_printf ( sb_err , _ ( L " %ls: Tried to change the read-only variable '%ls' \n " ) , L " set " , key ) ;
retcode = 1 ;
break ;
}
case ENV_INVALID :
{
sb_printf ( sb_err , _ ( L " %ls: Unknown error " ) , L " set " ) ;
retcode = 1 ;
break ;
}
}
sb_destroy ( & sb ) ;
return retcode ;
}
2011-12-26 19:18:46 -08:00
/**
2005-09-20 23:26:39 +10:00
Extract indexes from a destination argument of the form name [ index1 index2 . . . ]
2006-05-10 02:40:55 +10: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
2011-12-26 19:18:46 -08:00
\ param var_count the number of elements in the array to parse .
2006-05-10 02:40:55 +10:00
2006-06-17 23:07:08 +10:00
\ return the total number of indexes parsed , or - 1 on error
2005-09-20 23:26:39 +10:00
*/
2006-05-10 02:40:55 +10:00
static int parse_index ( array_list_t * indexes ,
const wchar_t * src ,
2006-06-04 19:35:32 +10:00
const wchar_t * name ,
int var_count )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
size_t len ;
2005-09-20 23:26:39 +10:00
int count = 0 ;
2006-05-10 02:40:55 +10:00
const wchar_t * src_orig = src ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( src = = 0 )
{
return 0 ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
while ( * src ! = L ' \0 ' & & ( iswalnum ( * src ) | | * src = = L ' _ ' ) )
{
src + + ;
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
if ( * src ! = L ' [ ' )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
sb_printf ( sb_err , _ ( BUILTIN_SET_ARG_COUNT ) , L " set " ) ;
2005-09-20 23:26:39 +10:00
return 0 ;
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
len = src - src_orig ;
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
if ( ( wcsncmp ( src_orig , name , len ) ! = 0 ) | | ( wcslen ( name ) ! = ( len ) ) )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
sb_printf ( sb_err ,
2006-05-10 02:40:55 +10:00
_ ( L " %ls: Multiple variable names specified in single call (%ls and %.*ls) \n " ) ,
2011-12-26 19:18:46 -08:00
L " set " ,
2006-05-10 02:40:55 +10:00
name ,
len ,
src_orig ) ;
return 0 ;
2005-09-20 23:26:39 +10:00
}
2006-05-10 02:40:55 +10:00
2011-12-26 19:18:46 -08:00
src + + ;
2006-05-10 02:40:55 +10:00
2011-12-26 19:18:46 -08:00
while ( iswspace ( * src ) )
2005-09-20 23:26:39 +10:00
{
src + + ;
}
2011-12-26 19:18:46 -08:00
while ( * src ! = L ' ] ' )
2005-09-20 23:26:39 +10:00
{
wchar_t * end ;
2011-12-26 19:18:46 -08:00
2007-01-09 13:20:05 +10:00
long l_ind ;
errno = 0 ;
2011-12-26 19:18:46 -08:00
2007-01-09 13:20:05 +10:00
l_ind = wcstol ( src , & end , 10 ) ;
2011-12-26 19:18:46 -08:00
if ( end = = src | | errno )
2005-09-20 23:26:39 +10:00
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err , _ ( L " %ls: Invalid index starting at '%ls' \n " ) , L " set " , src ) ;
2006-05-10 02:40:55 +10:00
return 0 ;
2005-09-20 23:26:39 +10:00
}
2006-06-04 19:35:32 +10:00
if ( l_ind < 0 )
{
l_ind = var_count + l_ind + 1 ;
}
2011-12-26 19:18:46 -08:00
2006-08-01 02:17:19 +10:00
al_push_long ( indexes , l_ind ) ;
2005-09-20 23:26:39 +10:00
src = end ;
count + + ;
2005-11-26 00:44:34 +10:00
while ( iswspace ( * src ) ) src + + ;
2005-09-20 23:26:39 +10:00
}
return count ;
}
2012-01-10 01:19:37 +05:30
static int parse_index2 ( std : : vector < long > & indexes ,
const wchar_t * src ,
const wchar_t * name ,
int var_count )
{
size_t len ;
int count = 0 ;
const wchar_t * src_orig = src ;
if ( src = = 0 )
{
return 0 ;
}
while ( * src ! = L ' \0 ' & & ( iswalnum ( * src ) | | * src = = L ' _ ' ) )
{
src + + ;
}
if ( * src ! = L ' [ ' )
{
sb_printf ( sb_err , _ ( BUILTIN_SET_ARG_COUNT ) , L " set " ) ;
return 0 ;
}
len = src - src_orig ;
if ( ( wcsncmp ( src_orig , name , len ) ! = 0 ) | | ( wcslen ( name ) ! = ( len ) ) )
{
sb_printf ( sb_err ,
_ ( L " %ls: Multiple variable names specified in single call (%ls and %.*ls) \n " ) ,
L " set " ,
name ,
len ,
src_orig ) ;
return 0 ;
}
src + + ;
while ( iswspace ( * src ) )
{
src + + ;
}
while ( * src ! = L ' ] ' )
{
wchar_t * end ;
long l_ind ;
errno = 0 ;
l_ind = wcstol ( src , & end , 10 ) ;
if ( end = = src | | errno )
{
sb_printf ( sb_err , _ ( L " %ls: Invalid index starting at '%ls' \n " ) , L " set " , src ) ;
return 0 ;
}
if ( l_ind < 0 )
{
l_ind = var_count + l_ind + 1 ;
}
indexes . push_back ( l_ind ) ;
src = end ;
count + + ;
while ( iswspace ( * src ) ) src + + ;
}
return count ;
}
2005-09-20 23:26:39 +10:00
/**
2006-04-19 22:43:15 +10:00
Update a list \ c list by writing copies ( using wcsdup ) of the
values specified by \ c values to the indexes specified by \ c
indexes . The previous entries at the specidied position will be
free ' d .
2006-06-05 06:14:51 +10:00
\ return 0 if the operation was successfull , non - zero otherwise
2005-09-20 23:26:39 +10:00
*/
2011-12-26 19:18:46 -08:00
static int update_values ( array_list_t * list ,
2005-09-20 23:26:39 +10:00
array_list_t * indexes ,
2011-12-26 19:18:46 -08:00
array_list_t * values )
2005-09-20 23:26:39 +10:00
{
int i ;
/* Replace values where needed */
2011-12-26 19:18:46 -08:00
for ( i = 0 ; i < al_get_count ( indexes ) ; i + + )
2005-09-20 23:26:39 +10:00
{
2006-08-01 02:17:19 +10:00
/*
The ' - 1 ' below is because the indices in fish are
2006-12-08 23:31:36 +10:00
one - based , but the array_list_t uses zero - based indices
2006-08-01 02:17:19 +10:00
*/
long ind = al_get_long ( indexes , i ) - 1 ;
2011-12-26 19:18:46 -08:00
const wchar_t * newv = ( const wchar_t * ) al_get ( values , i ) ;
2006-12-08 23:31:36 +10:00
if ( ind < 0 )
2006-06-05 06:14:51 +10:00
{
return 1 ;
}
2011-12-26 19:18:46 -08:00
2006-04-19 22:43:15 +10:00
free ( ( void * ) al_get ( list , ind ) ) ;
2011-12-26 19:18:46 -08:00
al_set ( list , ind , newv ! = 0 ? wcsdup ( newv ) : wcsdup ( L " " ) ) ;
2005-09-20 23:26:39 +10:00
}
2011-12-26 19:18:46 -08:00
2006-06-05 06:14:51 +10:00
return 0 ;
2005-09-20 23:26:39 +10:00
}
2012-01-10 01:19:37 +05:30
static int update_values2 ( wcstring_list_t & list ,
std : : vector < long > & indexes ,
wcstring_list_t & values )
{
int i ;
2005-09-20 23:26:39 +10:00
2012-01-10 01:19:37 +05:30
/* Replace values where needed */
for ( i = 0 ; i < indexes . size ( ) ; i + + )
{
/*
The ' - 1 ' below is because the indices in fish are
one - based , but the array_list_t uses zero - based indices
*/
long ind = indexes [ i ] - 1 ;
const wcstring newv = values [ i ] ;
if ( ind < 0 )
{
return 1 ;
}
// free((void *) al_get(list, ind));
list [ ind ] = newv ;
}
return 0 ;
}
2005-09-20 23:26:39 +10:00
/**
2006-08-01 02:17:19 +10:00
Return 1 if an array list of longs contains the specified
2005-09-20 23:26:39 +10:00
value , 0 otherwise
*/
2006-08-01 02:17:19 +10:00
static int al_contains_long ( array_list_t * list ,
long val )
2005-09-20 23:26:39 +10:00
{
int i ;
2011-12-26 19:18:46 -08:00
for ( i = 0 ; i < al_get_count ( list ) ; i + + )
2005-09-20 23:26:39 +10:00
{
2006-08-01 02:17:19 +10:00
long current = al_get_long ( list , i ) ;
2011-12-26 19:18:46 -08:00
if ( current ! = 0 & & current = = val )
2005-09-20 23:26:39 +10:00
{
return 1 ;
}
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
return 0 ;
}
/**
2011-12-26 19:18:46 -08:00
Erase from a list values at specified indexes
2005-09-20 23:26:39 +10:00
*/
2011-12-26 19:18:46 -08:00
static void erase_values ( array_list_t * list , array_list_t * indexes )
2005-09-20 23:26:39 +10:00
{
2006-10-26 20:22:53 +10:00
long i ;
2005-09-20 23:26:39 +10:00
array_list_t result ;
al_init ( & result ) ;
2011-12-26 19:18:46 -08:00
for ( i = 0 ; i < al_get_count ( list ) ; i + + )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
if ( ! al_contains_long ( indexes , i + 1 ) )
2005-09-20 23:26:39 +10:00
{
al_push ( & result , al_get ( list , i ) ) ;
}
2011-12-26 19:18:46 -08:00
else
2005-09-20 23:26:39 +10:00
{
2006-10-26 20:22:53 +10:00
free ( ( void * ) al_get ( list , i ) ) ;
2005-09-20 23:26:39 +10:00
}
}
2011-12-26 19:18:46 -08:00
al_truncate ( list , 0 ) ;
2005-09-20 23:26:39 +10:00
al_push_all ( list , & result ) ;
al_destroy ( & result ) ;
}
2012-01-10 01:19:37 +05:30
/**
Erase from a list of wcstring values at specified indexes
*/
static void erase_values2 ( wcstring_list_t & list , std : : vector < long > & indexes )
{
long i ;
wcstring_list_t result ;
// al_init(&result);
for ( i = 0 ; i < list . size ( ) ; i + + )
{
if ( std : : find ( indexes . begin ( ) , indexes . end ( ) , i + 1 ) ! = indexes . end ( ) )
{
result . push_back ( list [ i ] ) ;
}
else
{
// free( (void *)al_get(list, i));
}
}
// al_truncate(list,0);
list . clear ( ) ;
copy ( result . begin ( ) , result . end ( ) , back_inserter ( list ) ) ;
// al_destroy(&result);
}
2005-09-20 23:26:39 +10:00
/**
Print the names of all environment variables in the scope , with or without values ,
with or without escaping
*/
2011-12-26 19:18:46 -08:00
static void print_variables ( int include_values , int esc , int scope )
2005-09-20 23:26:39 +10:00
{
array_list_t names ;
int i ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
al_init ( & names ) ;
env_get_names ( & names , scope ) ;
2011-12-26 19:18:46 -08:00
2005-09-21 08:46:40 +10:00
sort_list ( & names ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
for ( i = 0 ; i < al_get_count ( & names ) ; i + + )
{
2005-09-23 06:16:52 +10:00
wchar_t * key = ( wchar_t * ) al_get ( & names , i ) ;
2006-10-20 01:24:18 +10:00
wchar_t * e_key = esc ? escape ( key , 0 ) : wcsdup ( key ) ;
2005-10-07 20:36:51 +10:00
2005-09-20 23:26:39 +10:00
sb_append ( sb_out , e_key ) ;
2011-12-26 19:18:46 -08:00
if ( include_values )
2005-09-20 23:26:39 +10:00
{
2012-01-14 02:42:17 -08:00
env_var_t value = env_get_string ( key ) ;
if ( ! value . missing ( ) )
2006-09-01 01:44:00 +10:00
{
2006-10-05 04:19:01 +10:00
int shorten = 0 ;
2011-12-26 19:18:46 -08:00
2012-01-10 01:19:37 +05:30
if ( value . length ( ) > 64 )
2006-10-05 04:19:01 +10:00
{
shorten = 1 ;
2012-01-14 02:42:17 -08:00
value . resize ( 60 ) ;
2006-10-05 04:19:01 +10:00
}
2011-12-26 19:18:46 -08:00
2012-01-14 02:42:17 -08:00
wcstring e_value = esc ? expand_escape_variable2 ( value ) : value ;
2011-12-26 19:18:46 -08:00
2012-01-14 02:42:17 -08:00
sb_append ( sb_out , L " " , e_value . c_str ( ) , NULL ) ;
2011-12-26 19:18:46 -08:00
2006-10-05 04:19:01 +10:00
if ( shorten )
{
sb_append ( sb_out , L " \u2026 " ) ;
}
2006-10-26 20:22:53 +10:00
2006-09-01 01:44:00 +10:00
}
2005-09-20 23:26:39 +10:00
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
sb_append ( sb_out , L " \n " ) ;
free ( e_key ) ;
}
2005-09-21 08:46:40 +10:00
al_destroy ( & names ) ;
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
*/
2011-12-26 19:18:46 -08:00
static int builtin_set ( wchar_t * * argv )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
2006-04-19 22:43:15 +10:00
/**
Variables used for parsing the argument list
*/
2010-10-08 08:43:57 +08:00
static const struct woption
2011-12-26 19:18:46 -08:00
long_options [ ] =
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
{
L " export " , no_argument , 0 , ' x '
2006-05-26 21:24:02 +10:00
}
,
2011-12-26 19:18:46 -08:00
{
L " global " , no_argument , 0 , ' g '
2006-05-26 21:24:02 +10:00
}
,
2011-12-26 19:18:46 -08:00
{
L " local " , no_argument , 0 , ' l '
2006-05-26 21:24:02 +10:00
}
,
2011-12-26 19:18:46 -08:00
{
L " erase " , no_argument , 0 , ' e '
2006-05-26 21:24:02 +10:00
}
,
2011-12-26 19:18:46 -08:00
{
L " names " , no_argument , 0 , ' n '
}
2006-05-26 21:24:02 +10:00
,
2011-12-26 19:18:46 -08:00
{
L " unexport " , no_argument , 0 , ' u '
}
2006-05-26 21:24:02 +10:00
,
2011-12-26 19:18:46 -08:00
{
L " universal " , no_argument , 0 , ' U '
}
2006-05-26 21:24:02 +10:00
,
2011-12-26 19:18:46 -08:00
{
L " query " , no_argument , 0 , ' q '
}
2006-05-26 21:24:02 +10:00
,
2011-12-26 19:18:46 -08:00
{
L " help " , no_argument , 0 , ' h '
}
2006-05-26 21:24:02 +10:00
,
2011-12-26 19:18:46 -08:00
{
0 , 0 , 0 , 0
2005-09-20 23:26:39 +10:00
}
}
;
2011-12-26 19:18:46 -08:00
2006-05-26 21:24:02 +10:00
const wchar_t * short_options = L " +xglenuUqh " ;
2005-09-20 23:26:39 +10:00
int argc = builtin_count_args ( argv ) ;
/*
Flags to set the work mode
*/
2011-12-26 19:18:46 -08:00
int local = 0 , global = 0 , exportv = 0 ;
2005-09-20 23:26:39 +10:00
int erase = 0 , list = 0 , unexport = 0 ;
2005-09-23 06:16:52 +10:00
int universal = 0 , query = 0 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
/*
Variables used for performing the actual work
*/
wchar_t * dest = 0 ;
int retcode = 0 ;
2006-05-10 02:40:55 +10:00
int scope ;
int slice = 0 ;
int i ;
2011-12-26 19:18:46 -08:00
2006-08-26 11:37:22 +10:00
wchar_t * bad_char ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
/* Parse options to obtain the requested operation and the modifiers */
woptind = 0 ;
2011-12-26 19:18:46 -08:00
while ( 1 )
2005-09-20 23:26:39 +10:00
{
int c = wgetopt_long ( argc , argv , short_options , long_options , 0 ) ;
2011-12-26 19:18:46 -08:00
if ( c = = - 1 )
2005-09-20 23:26:39 +10:00
{
break ;
}
2011-12-26 19:18:46 -08:00
switch ( c )
2005-09-20 23:26:39 +10:00
{
case 0 :
break ;
2006-05-26 21:24:02 +10:00
2005-09-20 23:26:39 +10:00
case ' e ' :
erase = 1 ;
break ;
2006-05-26 21:24:02 +10:00
2005-09-20 23:26:39 +10:00
case ' n ' :
list = 1 ;
break ;
2006-05-26 21:24:02 +10:00
2005-09-20 23:26:39 +10:00
case ' x ' :
2011-12-26 19:18:46 -08:00
exportv = 1 ;
2005-09-20 23:26:39 +10:00
break ;
2006-05-26 21:24:02 +10:00
2005-09-20 23:26:39 +10:00
case ' l ' :
local = 1 ;
break ;
2006-05-26 21:24:02 +10:00
2005-09-20 23:26:39 +10:00
case ' g ' :
global = 1 ;
break ;
2006-05-26 21:24:02 +10:00
2005-09-20 23:26:39 +10:00
case ' u ' :
unexport = 1 ;
break ;
2006-05-26 21:24:02 +10:00
2005-09-20 23:26:39 +10:00
case ' U ' :
universal = 1 ;
break ;
2006-05-26 21:24:02 +10:00
2005-09-23 06:16:52 +10:00
case ' q ' :
query = 1 ;
break ;
2006-05-26 21:24:02 +10:00
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_out ) ;
return 0 ;
2005-09-20 23:26:39 +10:00
case ' ? ' :
2007-01-22 00:55:27 +10:00
builtin_unknown_option ( argv [ 0 ] , argv [ woptind - 1 ] ) ;
2005-09-20 23:26:39 +10:00
return 1 ;
2006-05-26 21:24:02 +10:00
2005-09-20 23:26:39 +10:00
default :
break ;
}
}
2006-04-19 22:43:15 +10: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
*/
2011-12-26 19:18:46 -08:00
if ( query & & ( erase | | list | | global | | local | | universal | | exportv | | unexport ) )
2005-09-23 06:16:52 +10:00
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
2007-02-01 02:03:17 +10:00
BUILTIN_ERR_COMBO ,
argv [ 0 ] ) ;
2011-12-26 19:18:46 -08:00
2006-05-26 21:24:02 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2005-09-23 06:16:52 +10:00
return 1 ;
}
2011-12-26 19:18:46 -08:00
2005-09-23 06:16:52 +10:00
2006-04-19 22:43:15 +10:00
/* We can't both list and erase varaibles */
2011-12-26 19:18:46 -08:00
if ( erase & & list )
2005-09-20 23:26:39 +10:00
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
2007-02-01 02:03:17 +10:00
BUILTIN_ERR_COMBO ,
2011-12-26 19:18:46 -08:00
argv [ 0 ] ) ;
2006-01-04 22:51:02 +10:00
2006-05-26 21:24:02 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2005-09-20 23:26:39 +10:00
return 1 ;
}
2006-04-19 22:43:15 +10:00
/*
Variables can only have one scope
*/
2011-12-26 19:18:46 -08:00
if ( local + global + universal > 1 )
2005-09-20 23:26:39 +10:00
{
sb_printf ( sb_err ,
BUILTIN_ERR_GLOCAL ,
2007-02-01 02:03:17 +10:00
argv [ 0 ] ) ;
2006-05-26 21:24:02 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2005-09-20 23:26:39 +10:00
return 1 ;
}
2006-04-19 22:43:15 +10:00
/*
Variables can only have one export status
*/
2011-12-26 19:18:46 -08:00
if ( exportv & & unexport )
2005-09-20 23:26:39 +10:00
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
2005-09-20 23:26:39 +10:00
BUILTIN_ERR_EXPUNEXP ,
2007-02-01 02:03:17 +10:00
argv [ 0 ] ) ;
2006-05-26 21:24:02 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2005-09-20 23:26:39 +10:00
return 1 ;
}
2006-05-10 02:40:55 +10:00
/*
Calculate the scope value for variable assignement
*/
2011-12-26 19:18:46 -08:00
scope = ( local ? ENV_LOCAL : 0 ) | ( global ? ENV_GLOBAL : 0 ) | ( exportv ? ENV_EXPORT : 0 ) | ( unexport ? ENV_UNEXPORT : 0 ) | ( universal ? ENV_UNIVERSAL : 0 ) | ENV_USER ;
2006-05-10 02:40:55 +10:00
2005-09-23 06:16:52 +10:00
if ( query )
{
/*
2006-06-05 06:14:51 +10:00
Query mode . Return the number of variables that do not exist
2006-04-19 22:43:15 +10:00
out of the specified variables .
2005-09-23 06:16:52 +10:00
*/
int i ;
for ( i = woptind ; i < argc ; i + + )
{
2007-01-31 06:43:44 +10:00
wchar_t * arg = argv [ i ] ;
int slice = 0 ;
if ( ! ( dest = wcsdup ( arg ) ) )
{
2011-12-26 19:18:46 -08:00
DIE_MEM ( ) ;
2007-01-31 06:43:44 +10:00
}
if ( wcschr ( dest , L ' [ ' ) )
{
slice = 1 ;
* wcschr ( dest , L ' [ ' ) = 0 ;
}
2011-12-26 19:18:46 -08:00
2007-01-31 06:43:44 +10:00
if ( slice )
{
2012-01-10 01:19:37 +05:30
std : : vector < long > indexes ;
wcstring_list_t result ;
2007-01-31 06:43:44 +10:00
int j ;
2011-12-26 19:18:46 -08:00
2012-01-10 01:19:37 +05:30
// al_init( &result );
// al_init( &indexes );
2012-01-14 02:42:17 -08:00
env_var_t dest_str = env_get_string ( dest ) ;
if ( ! dest_str . missing ( ) )
tokenize_variable_array2 ( dest_str , result ) ;
2011-12-26 19:18:46 -08:00
2012-01-10 01:19:37 +05:30
if ( ! parse_index2 ( indexes , arg , dest , result . size ( ) ) )
2007-01-31 06:43:44 +10:00
{
builtin_print_help ( argv [ 0 ] , sb_err ) ;
retcode = 1 ;
break ;
}
2012-01-10 01:19:37 +05:30
for ( j = 0 ; j < indexes . size ( ) ; j + + )
2007-01-31 06:43:44 +10:00
{
2012-01-10 01:19:37 +05:30
long idx = indexes [ j ] ;
if ( idx < 1 | | idx > result . size ( ) )
2007-01-31 06:43:44 +10:00
{
retcode + + ;
}
}
}
else
2006-04-19 22:43:15 +10:00
{
2007-01-31 06:43:44 +10:00
if ( ! env_exist ( arg , scope ) )
{
retcode + + ;
}
2006-04-19 22:43:15 +10:00
}
2011-12-26 19:18:46 -08:00
2007-01-31 06:43:44 +10:00
free ( dest ) ;
2011-12-26 19:18:46 -08:00
2005-09-23 06:16:52 +10:00
}
return retcode ;
}
2011-12-26 19:18:46 -08:00
if ( list )
2006-09-01 01:44:00 +10:00
{
/* Maybe we should issue an error if there are any other arguments? */
print_variables ( 0 , 0 , scope ) ;
return 0 ;
2011-12-26 19:18:46 -08:00
}
2006-05-10 02:40:55 +10:00
if ( woptind = = argc )
2005-09-20 23:26:39 +10:00
{
2006-05-10 02:40:55 +10:00
/*
Print values of variables
*/
2011-12-26 19:18:46 -08:00
if ( erase )
2005-12-08 00:48:49 +10:00
{
2006-05-10 02:40:55 +10:00
sb_printf ( sb_err ,
2011-12-26 19:18:46 -08:00
_ ( L " %ls: Erase needs a variable name \n %ls \n " ) ,
2007-02-01 02:03:17 +10:00
argv [ 0 ] ) ;
2011-12-26 19:18:46 -08:00
2006-05-26 21:24:02 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-05-10 02:40:55 +10:00
retcode = 1 ;
}
else
{
print_variables ( 1 , 1 , scope ) ;
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
return retcode ;
2005-09-20 23:26:39 +10:00
}
2006-05-10 02:40:55 +10:00
if ( ! ( dest = wcsdup ( argv [ woptind ] ) ) )
{
2011-12-26 19:18:46 -08:00
DIE_MEM ( ) ;
2006-05-10 02:40:55 +10:00
}
2005-09-20 23:26:39 +10:00
2006-05-10 02:40:55 +10:00
if ( wcschr ( dest , L ' [ ' ) )
2005-09-20 23:26:39 +10:00
{
2006-05-10 02:40:55 +10:00
slice = 1 ;
* wcschr ( dest , L ' [ ' ) = 0 ;
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
if ( ! wcslen ( dest ) )
{
free ( dest ) ;
sb_printf ( sb_err , BUILTIN_ERR_VARNAME_ZERO , argv [ 0 ] ) ;
2006-06-04 08:31:50 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-05-10 02:40:55 +10:00
return 1 ;
2005-09-20 23:26:39 +10:00
}
2011-12-26 19:18:46 -08:00
2006-08-26 11:37:22 +10:00
if ( ( bad_char = wcsvarname ( dest ) ) )
{
sb_printf ( sb_err , BUILTIN_ERR_VARCHAR , argv [ 0 ] , * bad_char ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
free ( dest ) ;
return 1 ;
}
2011-12-26 19:18:46 -08:00
2006-06-05 06:14:51 +10:00
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 ;
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
/*
set assignment can work in two modes , either using slices or
using the whole array . We detect which mode is used here .
*/
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
if ( slice )
2006-04-21 04:29:44 +10:00
{
2006-05-10 02:40:55 +10:00
/*
Slice mode
*/
int idx_count , val_count ;
2012-01-10 01:19:37 +05:30
wcstring_list_t values ;
std : : vector < long > indexes ;
wcstring_list_t result ;
2011-12-26 19:18:46 -08:00
2012-01-10 01:19:37 +05:30
// al_init(&values);
// al_init(&indexes);
// al_init(&result);
2011-12-26 19:18:46 -08:00
2012-01-14 02:42:17 -08:00
const env_var_t dest_str = env_get_string ( dest ) ;
if ( ! dest_str . missing ( ) )
tokenize_variable_array2 ( dest_str , result ) ;
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
for ( ; woptind < argc ; woptind + + )
2011-12-26 19:18:46 -08:00
{
2012-01-10 01:19:37 +05:30
if ( ! parse_index2 ( indexes , argv [ woptind ] , dest , result . size ( ) ) )
2006-04-21 04:29:44 +10:00
{
2006-06-04 08:31:50 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-05-10 02:40:55 +10:00
retcode = 1 ;
break ;
2006-04-21 04:29:44 +10:00
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
val_count = argc - woptind - 1 ;
2012-01-10 01:19:37 +05:30
idx_count = indexes . size ( ) ;
2006-05-10 02:40:55 +10:00
if ( ! erase )
2006-04-21 04:29:44 +10:00
{
2006-05-10 02:40:55 +10:00
if ( val_count < idx_count )
2006-04-21 04:29:44 +10:00
{
2006-05-10 02:40:55 +10:00
sb_printf ( sb_err , _ ( BUILTIN_SET_ARG_COUNT ) , argv [ 0 ] ) ;
2006-06-04 08:31:50 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-05-10 02:40:55 +10:00
retcode = 1 ;
break ;
}
if ( val_count = = idx_count )
{
woptind + + ;
break ;
2006-04-21 04:29:44 +10:00
}
}
2011-12-26 19:18:46 -08:00
}
2006-04-21 04:29:44 +10:00
2006-05-10 02:40:55 +10:00
if ( ! retcode )
2006-04-21 04:29:44 +10:00
{
2006-05-10 02:40:55 +10:00
/*
Slice indexes have been calculated , do the actual work
*/
2006-04-21 04:29:44 +10:00
2006-05-10 02:40:55 +10:00
if ( erase )
{
2012-01-10 01:19:37 +05:30
erase_values2 ( result , indexes ) ;
my_env_set2 ( dest , result , scope ) ;
2006-05-10 02:40:55 +10:00
}
else
{
2012-01-10 01:19:37 +05:30
wcstring_list_t value ;
// al_init(&value);
2005-09-20 23:26:39 +10:00
2011-12-26 19:18:46 -08:00
while ( woptind < argc )
2006-05-10 02:40:55 +10:00
{
2012-01-10 01:19:37 +05:30
value . push_back ( argv [ woptind + + ] ) ;
2006-05-10 02:40:55 +10:00
}
2005-09-20 23:26:39 +10:00
2012-01-10 01:19:37 +05:30
if ( update_values2 ( result ,
indexes ,
value ) )
2006-06-05 06:14:51 +10:00
{
sb_printf ( sb_err , L " %ls: " , argv [ 0 ] ) ;
sb_printf ( sb_err , ARRAY_BOUNDS_ERR ) ;
sb_append ( sb_err , L " \n " ) ;
}
2011-12-26 19:18:46 -08:00
2012-01-10 01:19:37 +05:30
my_env_set2 ( dest ,
result ,
2006-05-10 02:40:55 +10:00
scope ) ;
2011-12-26 19:18:46 -08:00
2012-01-10 01:19:37 +05:30
// al_destroy( &value );
2011-12-26 19:18:46 -08:00
}
2006-05-10 02:40:55 +10:00
}
2005-09-20 23:26:39 +10:00
2012-01-10 01:19:37 +05:30
// al_foreach( &result, &free );
// al_destroy( &result );
2006-06-04 19:35:32 +10:00
2012-01-10 01:19:37 +05:30
// al_destroy(&indexes);
// al_destroy(&values);
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
}
2006-05-10 02:40:55 +10:00
else
2005-09-20 23:26:39 +10:00
{
2006-05-10 02:40:55 +10:00
woptind + + ;
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
/*
No slicing
*/
if ( erase )
2005-09-20 23:26:39 +10:00
{
2006-05-10 02:40:55 +10:00
if ( woptind ! = argc )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
sb_printf ( sb_err ,
2007-02-01 02:03:17 +10:00
_ ( L " %ls: Values cannot be specfied with erase \n " ) ,
argv [ 0 ] ) ;
2006-06-04 08:31:50 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2006-05-10 02:40:55 +10:00
retcode = 1 ;
2005-09-20 23:26:39 +10:00
}
2006-05-10 02:40:55 +10:00
else
2005-09-20 23:26:39 +10:00
{
2006-06-05 06:14:51 +10:00
retcode = env_remove ( dest , scope ) ;
2005-09-20 23:26:39 +10:00
}
}
2006-05-10 02:40:55 +10:00
else
2005-09-20 23:26:39 +10:00
{
2006-05-10 02:40:55 +10:00
array_list_t val ;
al_init ( & val ) ;
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
for ( i = woptind ; i < argc ; i + + )
2005-09-20 23:26:39 +10:00
{
2006-05-10 02:40:55 +10:00
al_push ( & val , argv [ i ] ) ;
2005-09-20 23:26:39 +10:00
}
2006-05-10 02:40:55 +10:00
retcode = my_env_set ( dest , & val , scope ) ;
2011-12-26 19:18:46 -08:00
al_destroy ( & val ) ;
}
2005-09-20 23:26:39 +10:00
}
2011-12-26 19:18:46 -08:00
2006-05-10 02:40:55 +10:00
free ( dest ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
return retcode ;
2006-05-10 02:40:55 +10:00
2005-09-20 23:26:39 +10:00
}