2005-09-20 23:26:39 +10:00
/** \file builtin_set.c Functions defining the set builtin
Functions used for implementing the set builtin .
*/
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <wctype.h>
# include <sys/types.h>
# include <termios.h>
# include <signal.h>
# include "config.h"
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-01-04 22:51:02 +10:00
# include "translate.h"
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 )
{
return contains_str ( env ,
L " PATH " ,
L " CDPATH " ,
( void * ) 0 ) ;
}
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 ;
if ( is_path_variable ( key ) )
2006-04-11 01:36:26 +10:00
{
2006-05-10 02:40:55 +10:00
int error = 0 ;
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 ;
struct stat buff ;
wchar_t * dir = ( wchar_t * ) al_get ( val , i ) ;
if ( wstat ( dir , & buff ) )
{
error = 1 ;
show_perror = 1 ;
}
if ( ! ( S_IFDIR & buff . st_mode ) )
{
error = 1 ;
}
if ( error )
{
wchar_t * colon ;
sb_printf ( sb_err ,
_ ( BUILTIN_SET_PATH_ERROR ) ,
L " set " ,
dir ,
key ) ;
2006-05-19 18:58:13 +10:00
2006-05-10 02:40:55 +10:00
colon = wcschr ( dir , L ' : ' ) ;
if ( colon & & * ( colon + 1 ) )
{
show_hint = 1 ;
}
2006-05-19 18:58:13 +10:00
2006-05-10 02:40:55 +10:00
}
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 ;
2006-04-11 01:36:26 +10:00
}
2006-05-10 02:40:55 +10: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 + + )
{
sb_append ( & sb , ( wchar_t * ) al_get ( val , i ) ) ;
if ( i < al_get_count ( val ) - 1 )
{
sb_append ( & sb , ARRAY_SEP_STR ) ;
}
}
val_str = ( wchar_t * ) sb . buff ;
2005-09-20 23:26:39 +10: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 ;
}
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
/**
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
\ return the 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 ,
const wchar_t * name )
2005-09-20 23:26:39 +10:00
{
2006-05-10 02:40:55 +10:00
int 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 ;
2005-09-20 23:26:39 +10:00
if ( src = = 0 )
{
return 0 ;
}
while ( * src ! = L ' \0 ' & & ( iswalnum ( * src ) | | * src = = L ' _ ' ) )
{
src + + ;
}
2006-05-10 02:40:55 +10:00
if ( * src ! = L ' [ ' )
2005-09-20 23:26:39 +10:00
{
2006-05-10 02:40:55 +10:00
sb_printf ( sb_err , _ ( BUILTIN_SET_ARG_COUNT ) , L " set " ) ;
2005-09-20 23:26:39 +10:00
return 0 ;
}
2006-05-19 18:58:13 +10:00
2006-05-10 02:40:55 +10:00
len = src - src_orig ;
2005-09-20 23:26:39 +10: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
{
2006-05-10 02:40:55 +10:00
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 ;
2005-09-20 23:26:39 +10:00
}
2006-05-10 02:40:55 +10:00
src + + ;
2005-11-26 00:44:34 +10:00
while ( iswspace ( * src ) )
2005-09-20 23:26:39 +10:00
{
src + + ;
}
while ( * src ! = L ' ] ' )
{
wchar_t * end ;
long l_ind = wcstol ( src , & end , 10 ) ;
if ( end = = src )
{
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-05-10 02:40:55 +10:00
2005-09-20 23:26:39 +10:00
int * ind = ( int * ) calloc ( 1 , sizeof ( int ) ) ;
* ind = ( int ) l_ind ;
al_push ( indexes , ind ) ;
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 ;
}
/**
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-05-19 18:58:13 +10:00
\ return The number of elements in the list after the modifications
have been made
2005-09-20 23:26:39 +10:00
*/
static int update_values ( array_list_t * list ,
array_list_t * indexes ,
array_list_t * values )
{
int i ;
/* Replace values where needed */
for ( i = 0 ; i < al_get_count ( indexes ) ; i + + )
{
int ind = * ( int * ) al_get ( indexes , i ) - 1 ;
void * new = ( void * ) al_get ( values , i ) ;
2006-04-19 22:43:15 +10:00
free ( ( void * ) al_get ( list , ind ) ) ;
2005-09-20 23:26:39 +10:00
al_set ( list , ind , new ! = 0 ? wcsdup ( new ) : wcsdup ( L " " ) ) ;
}
return al_get_count ( list ) ;
}
/**
Return 1 if an array list of int * pointers contains the specified
value , 0 otherwise
*/
static int al_contains_int ( array_list_t * list ,
int val )
{
int i ;
for ( i = 0 ; i < al_get_count ( list ) ; i + + )
{
int * current = ( int * ) al_get ( list , i ) ;
2006-05-19 18:58:13 +10:00
if ( current ! = 0 & & * current = = val )
2005-09-20 23:26:39 +10:00
{
return 1 ;
}
}
return 0 ;
}
/**
Erase from a list values at specified indexes
*/
2006-05-10 02:40:55 +10:00
static void erase_values ( array_list_t * list , array_list_t * indexes )
2005-09-20 23:26:39 +10:00
{
int i ;
array_list_t result ;
al_init ( & result ) ;
for ( i = 0 ; i < al_get_count ( list ) ; i + + )
{
if ( ! al_contains_int ( indexes , i + 1 ) )
{
al_push ( & result , al_get ( list , i ) ) ;
}
else
{
free ( ( void * ) al_get ( list , i ) ) ;
}
}
al_truncate ( list , 0 ) ;
al_push_all ( list , & result ) ;
al_destroy ( & result ) ;
}
/**
Print the names of all environment variables in the scope , with or without values ,
with or without escaping
*/
2005-10-07 20:36:51 +10: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 ;
2005-09-21 08:46:40 +10:00
2005-09-20 23:26:39 +10:00
al_init ( & names ) ;
env_get_names ( & names , scope ) ;
2005-09-21 08:46:40 +10:00
sort_list ( & names ) ;
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 ) ;
2005-10-07 20:36:51 +10:00
wchar_t * e_key = esc ? escape ( key , 1 ) : wcsdup ( key ) ;
2005-09-20 23:26:39 +10:00
sb_append ( sb_out , e_key ) ;
2005-09-21 08:46:40 +10:00
2005-09-20 23:26:39 +10:00
if ( include_values )
{
wchar_t * value = env_get ( key ) ;
2005-10-07 20:36:51 +10:00
wchar_t * e_value ;
e_value = esc ? expand_escape_variable ( value ) : wcsdup ( value ) ;
2005-10-01 04:28:26 +10:00
sb_append2 ( sb_out , L " " , e_value , ( void * ) 0 ) ;
2005-09-20 23:26:39 +10:00
free ( e_value ) ;
}
2005-09-21 08:46:40 +10: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
*/
int builtin_set ( wchar_t * * argv )
{
2006-04-19 22:43:15 +10:00
/**
Variables used for parsing the argument list
*/
2005-09-20 23:26:39 +10:00
const static struct woption
long_options [ ] =
{
{
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 '
} ,
2005-09-23 06:16:52 +10:00
{
L " query " , no_argument , 0 , ' q '
} ,
2005-09-20 23:26:39 +10:00
{
0 , 0 , 0 , 0
}
}
;
2006-04-19 22:43:15 +10:00
const wchar_t * short_options = L " +xglenuUq " ;
2005-09-20 23:26:39 +10:00
int argc = builtin_count_args ( argv ) ;
/*
Flags to set the work mode
*/
int local = 0 , global = 0 , export = 0 ;
int erase = 0 , list = 0 , unexport = 0 ;
2005-09-23 06:16:52 +10:00
int universal = 0 , query = 0 ;
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 ;
2005-09-20 23:26:39 +10:00
/* Parse options to obtain the requested operation and the modifiers */
woptind = 0 ;
while ( 1 )
{
int c = wgetopt_long ( argc , argv , short_options , long_options , 0 ) ;
if ( c = = - 1 )
{
break ;
}
switch ( c )
{
case 0 :
break ;
case ' e ' :
erase = 1 ;
break ;
case ' n ' :
list = 1 ;
break ;
case ' x ' :
export = 1 ;
break ;
case ' l ' :
local = 1 ;
break ;
case ' g ' :
global = 1 ;
break ;
case ' u ' :
unexport = 1 ;
break ;
case ' U ' :
universal = 1 ;
break ;
2005-09-23 06:16:52 +10:00
case ' q ' :
query = 1 ;
break ;
2005-09-20 23:26:39 +10:00
case ' ? ' :
return 1 ;
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
*/
2005-09-23 06:16:52 +10:00
if ( query & & ( erase | | list | | global | | local | | universal | | export | | unexport ) )
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
BUILTIN_ERR_COMBO2 ,
2005-09-23 06:16:52 +10:00
argv [ 0 ] ,
2006-01-04 22:51:02 +10:00
parser_current_line ( ) ) ;
2006-05-10 02:40:55 +10:00
// builtin_print_help( argv[0], sb_err );
2005-09-23 06:16:52 +10:00
return 1 ;
}
2006-04-19 22:43:15 +10:00
/* We can't both list and erase varaibles */
2005-09-20 23:26:39 +10:00
if ( erase & & list )
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
BUILTIN_ERR_COMBO2 ,
2005-09-20 23:26:39 +10:00
argv [ 0 ] ,
2006-01-04 22:51:02 +10:00
parser_current_line ( ) ) ;
2006-05-10 02:40:55 +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
*/
2005-09-20 23:26:39 +10:00
if ( local + global + universal > 1 )
{
sb_printf ( sb_err ,
BUILTIN_ERR_GLOCAL ,
2006-01-04 22:51:02 +10:00
argv [ 0 ] ,
2005-09-20 23:26:39 +10:00
parser_current_line ( ) ) ;
2006-05-10 02:40:55 +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
*/
2005-09-20 23:26:39 +10:00
if ( export & & unexport )
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
2005-09-20 23:26:39 +10:00
BUILTIN_ERR_EXPUNEXP ,
2006-01-04 22:51:02 +10:00
argv [ 0 ] ,
parser_current_line ( ) ) ;
2006-05-10 02:40:55 +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
*/
scope = ( local ? ENV_LOCAL : 0 ) | ( global ? ENV_GLOBAL : 0 ) | ( export ? ENV_EXPORT : 0 ) | ( unexport ? ENV_UNEXPORT : 0 ) | ( universal ? ENV_UNIVERSAL : 0 ) | ENV_USER ;
2005-09-23 06:16:52 +10:00
if ( query )
{
/*
2006-04-19 22:43:15 +10:00
Query mode . Return the number variables that do not exist
out of the specified variables .
2005-09-23 06:16:52 +10:00
*/
int i ;
for ( i = woptind ; i < argc ; i + + )
{
2005-09-27 00:47:03 +10:00
if ( ! env_exist ( argv [ i ] ) )
2006-04-19 22:43:15 +10:00
{
2005-09-23 06:16:52 +10:00
retcode + + ;
2006-04-19 22:43:15 +10:00
}
2005-09-23 06:16:52 +10:00
}
return retcode ;
}
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
*/
if ( erase )
2005-12-08 00:48:49 +10:00
{
2006-05-10 02:40:55 +10:00
sb_printf ( sb_err ,
_ ( L " %ls: Erase needs a variable name \n %ls \n " ) ,
argv [ 0 ] ,
parser_current_line ( ) ) ;
// builtin_print_help( argv[0], sb_err );
retcode = 1 ;
}
else
{
print_variables ( 1 , 1 , scope ) ;
}
return retcode ;
2005-09-20 23:26:39 +10:00
}
2006-05-10 02:40:55 +10:00
if ( list )
{
/* Maybe we should issue an error if there are any other arguments? */
print_variables ( 0 , 0 , scope ) ;
return 0 ;
}
if ( ! ( dest = wcsdup ( argv [ woptind ] ) ) )
{
die_mem ( ) ;
}
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 ;
}
if ( ! wcslen ( dest ) )
{
free ( dest ) ;
sb_printf ( sb_err , BUILTIN_ERR_VARNAME_ZERO , argv [ 0 ] ) ;
return 1 ;
2005-09-20 23:26:39 +10: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 .
*/
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 ;
array_list_t values ;
array_list_t indexes ;
al_init ( & values ) ;
al_init ( & indexes ) ;
for ( ; woptind < argc ; woptind + + )
{
if ( ! parse_index ( & indexes , argv [ woptind ] , dest ) )
2006-04-21 04:29:44 +10:00
{
2006-05-10 02:40:55 +10:00
retcode = 1 ;
break ;
2006-04-21 04:29:44 +10:00
}
2006-05-10 02:40:55 +10:00
val_count = argc - woptind - 1 ;
idx_count = al_get_count ( & indexes ) ;
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 ] ) ;
retcode = 1 ;
break ;
}
if ( val_count = = idx_count )
{
woptind + + ;
break ;
2006-04-21 04:29:44 +10:00
}
}
2006-05-10 02:40:55 +10: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
array_list_t result ;
al_init ( & result ) ;
2006-04-21 04:29:44 +10:00
2006-05-10 02:40:55 +10:00
expand_variable_array ( env_get ( dest ) , & result ) ;
if ( erase )
{
erase_values ( & result , & indexes ) ;
my_env_set ( dest , & result , scope ) ;
}
else
{
array_list_t value ;
al_init ( & value ) ;
2005-09-20 23:26:39 +10:00
2006-05-10 02:40:55 +10:00
while ( woptind < argc )
{
al_push ( & value , argv [ woptind + + ] ) ;
}
2005-09-20 23:26:39 +10:00
2006-05-10 02:40:55 +10:00
update_values ( & result ,
& indexes ,
& value ) ;
my_env_set ( dest ,
& result ,
scope ) ;
al_destroy ( & value ) ;
}
al_foreach ( & result , ( void ( * ) ( const void * ) ) & free ) ;
al_destroy ( & result ) ;
}
2005-09-20 23:26:39 +10:00
2006-05-10 02:40:55 +10:00
al_foreach ( & indexes , ( void ( * ) ( const void * ) ) & free ) ;
al_destroy ( & indexes ) ;
al_destroy ( & values ) ;
2006-04-19 22:43:15 +10: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 + + ;
2005-09-20 23:26:39 +10: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
{
2006-05-10 02:40:55 +10:00
sb_printf ( sb_err ,
_ ( L " %ls: Values cannot be specfied with erase \n %ls \n " ) ,
2006-01-04 22:51:02 +10:00
argv [ 0 ] ,
parser_current_line ( ) ) ;
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-05-10 02:40:55 +10:00
env_remove ( dest , ENV_USER ) ;
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 ) ;
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 ) ;
al_destroy ( & val ) ;
}
2005-09-20 23:26:39 +10:00
}
2006-05-10 02:40:55 +10:00
free ( dest ) ;
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
}