2005-09-20 23:26:39 +10:00
/** \file env.c
Functions for setting and getting environment variables .
*/
2005-10-05 19:58:00 +10:00
# include "config.h"
2005-09-20 23:26:39 +10:00
# include <stdlib.h>
# include <wchar.h>
# include <string.h>
# include <stdio.h>
# include <locale.h>
# include <unistd.h>
# include <signal.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <pwd.h>
# if HAVE_NCURSES_H
# include <ncurses.h>
# else
# include <curses.h>
# endif
# if HAVE_TERMIO_H
# include <termio.h>
# endif
# include <term.h>
2005-10-22 20:06:05 +10:00
# include <errno.h>
2005-09-20 23:26:39 +10:00
# include "util.h"
# include "wutil.h"
# include "proc.h"
# include "common.h"
# include "env.h"
# include "sanity.h"
# include "expand.h"
# include "history.h"
# include "reader.h"
# include "parser.h"
# include "env_universal.h"
2005-09-27 00:47:03 +10:00
# include "input_common.h"
2005-10-06 08:37:08 +10:00
# include "event.h"
2005-09-20 23:26:39 +10:00
/**
Command used to start fishd
*/
2005-11-24 04:57:10 +10:00
# define FISHD_CMD L"if which fishd > / dev / null; fishd ^ / tmp / fishd.%s.log; end"
2005-09-20 23:26:39 +10:00
2005-10-25 01:26:25 +10:00
/**
Value denoting a null string
*/
2005-09-27 00:47:03 +10:00
# define ENV_NULL L"\x1d"
2005-09-20 23:26:39 +10:00
/**
At init , we read all the environment variables from this array
*/
extern char * * environ ;
/**
Struct representing one level in the function variable stack
*/
typedef struct env_node
{
/**
Variable table
*/
hash_table_t env ;
/**
Does this node imply a new variable scope ? If yes , all
non - global variables below this one in the stack are
invisible . If new_scope is set for the global variable node ,
the universe will explode .
*/
int new_scope ;
/**
Does this node contain any variables which are exported to subshells
*/
int export ;
/**
Pointer to next level
*/
struct env_node * next ;
}
2005-10-06 08:37:08 +10:00
env_node_t ;
2005-09-20 23:26:39 +10:00
/**
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 */
}
2005-10-06 08:37:08 +10:00
var_entry_t ;
2005-09-20 23:26:39 +10:00
/**
Top node on the function stack
*/
static env_node_t * top = 0 ;
/**
Bottom node on the function stack
*/
static env_node_t * global_env = 0 ;
/**
Table for global variables
*/
static hash_table_t * global ;
/**
Table of variables that may not be set using the set command .
*/
static hash_table_t env_read_only ;
2005-10-23 22:14:29 +10:00
/**
Table of variables whose value is dynamically calculated , such as umask , status , etc
*/
static hash_table_t env_electric ;
2005-09-20 23:26:39 +10:00
/**
Exported variable array used by execv
*/
static char * * export_arr = 0 ;
2005-09-23 06:16:52 +10:00
/**
Buffer used for storing string contents for export_arr
*/
static buffer_t export_buffer ;
2005-09-20 23:26:39 +10:00
/**
Flag for checking if we need to regenerate the exported variable
array
*/
static int has_changed = 1 ;
/**
Free hash key and hash value
*/
static void clear_hash_entry ( const void * key , const void * data )
{
var_entry_t * entry = ( var_entry_t * ) data ;
if ( entry - > export )
has_changed = 1 ;
free ( ( void * ) key ) ;
free ( ( void * ) data ) ;
}
/**
This stringbuffer is used to store the value of dynamically
generated variables , such as history .
*/
static string_buffer_t dyn_var ;
/**
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 ;
/**
When fishd isn ' t started , this function is provided to
2005-10-03 23:09:37 +10:00
env_universal as a callback , it tries to start up fishd . It ' s
implementation is a bit of a hack , since it evaluates a bit of
shellscript , and it might be used at times when that might not be
the best idea .
2005-09-20 23:26:39 +10:00
*/
static void start_fishd ( )
{
string_buffer_t cmd ;
struct passwd * pw ;
sb_init ( & cmd ) ;
pw = getpwuid ( getuid ( ) ) ;
2005-11-29 20:13:03 +10:00
debug ( 3 , L " Spawning new copy of fishd " ) ;
2005-09-20 23:26:39 +10:00
if ( ! pw )
{
debug ( 0 , L " Could not get user information " ) ;
return ;
}
sb_printf ( & cmd , FISHD_CMD , pw - > pw_name ) ;
eval ( ( wchar_t * ) cmd . buff ,
0 ,
TOP ) ;
sb_destroy ( & cmd ) ;
}
2005-10-23 22:14:29 +10:00
/**
Return the current umask value .
*/
static mode_t get_umask ( )
{
mode_t res ;
res = umask ( 0 ) ;
umask ( res ) ;
return res ;
}
/**
Universal variable callback function . This function makes sure the
proper events are triggered when an event occurs .
*/
2005-10-12 05:23:43 +10:00
static void universal_callback ( int type ,
const wchar_t * name ,
const wchar_t * val )
{
wchar_t * str = 0 ;
switch ( type )
{
case SET :
case SET_EXPORT :
str = L " SET " ;
break ;
case ERASE :
str = L " ERASE " ;
break ;
}
if ( str )
{
event_t ev ;
has_changed = 1 ;
ev . type = EVENT_VARIABLE ;
2005-10-12 05:31:16 +10:00
ev . param1 . variable = name ;
2005-10-12 05:23:43 +10:00
ev . function_name = 0 ;
2005-12-12 08:21:01 +10:00
al_init ( & ev . arguments ) ;
al_push ( & ev . arguments , L " VARIABLE " ) ;
al_push ( & ev . arguments , str ) ;
al_push ( & ev . arguments , name ) ;
event_fire ( & ev ) ;
al_destroy ( & ev . arguments ) ;
2005-10-12 05:23:43 +10:00
}
}
2005-09-20 23:26:39 +10:00
void env_init ( )
{
char * * p ;
2005-10-23 20:22:32 +10:00
struct passwd * pw ;
2005-10-25 19:39:45 +10:00
wchar_t * uname , * path ;
2005-09-20 23:26:39 +10:00
sb_init ( & dyn_var ) ;
2005-09-23 06:16:52 +10:00
b_init ( & export_buffer ) ;
2005-09-20 23:26:39 +10:00
/*
These variables can not be altered directly by the user
*/
hash_init ( & env_read_only , & hash_wcs_func , & hash_wcs_cmp ) ;
hash_put ( & env_read_only , L " status " , L " " ) ;
hash_put ( & env_read_only , L " history " , L " " ) ;
hash_put ( & env_read_only , L " _ " , L " " ) ;
hash_put ( & env_read_only , L " LINES " , L " " ) ;
hash_put ( & env_read_only , L " COLUMNS " , L " " ) ;
hash_put ( & env_read_only , L " PWD " , L " " ) ;
2005-10-14 21:40:33 +10:00
2005-10-23 22:14:29 +10:00
/*
Names of all dynamically calculated variables
*/
hash_init ( & env_electric , & hash_wcs_func , & hash_wcs_cmp ) ;
hash_put ( & env_electric , L " history " , L " " ) ;
hash_put ( & env_electric , L " status " , L " " ) ;
hash_put ( & env_electric , L " umask " , L " " ) ;
2005-09-20 23:26:39 +10:00
/*
2005-10-23 20:22:32 +10:00
HOME and USER should be writeable by root , since this can be a
2005-09-20 23:26:39 +10:00
convenient way to install software .
*/
if ( getuid ( ) ! = 0 )
2005-10-23 20:22:32 +10:00
{
2005-09-20 23:26:39 +10:00
hash_put ( & env_read_only , L " HOME " , L " " ) ;
2005-10-23 20:22:32 +10:00
hash_put ( & env_read_only , L " USER " , L " " ) ;
}
2005-09-20 23:26:39 +10:00
top = malloc ( sizeof ( env_node_t ) ) ;
top - > next = 0 ;
top - > new_scope = 0 ;
top - > export = 0 ;
hash_init ( & top - > env , & hash_wcs_func , & hash_wcs_cmp ) ;
global_env = top ;
global = & top - > env ;
2005-10-23 20:22:32 +10:00
2005-09-20 23:26:39 +10:00
/*
Import environment variables
*/
for ( p = environ ; * p ; p + + )
{
wchar_t * key , * val ;
wchar_t * pos ;
key = str2wcs ( * p ) ;
2005-10-25 19:39:45 +10:00
2005-09-20 23:26:39 +10:00
if ( ! key )
continue ;
val = wcschr ( key , L ' = ' ) ;
2005-10-25 19:39:45 +10:00
2005-09-20 23:26:39 +10:00
if ( val = = 0 )
env_set ( key , L " " , ENV_EXPORT ) ;
else
{
* val = L ' \0 ' ;
val + + ;
pos = val ;
2005-09-24 09:15:38 +10:00
//fwprintf( stderr, L"Set $%ls to %ls\n", key, val );
2005-09-20 23:26:39 +10:00
while ( * pos )
{
if ( * pos = = L ' : ' )
* pos = ARRAY_SEP ;
pos + + ;
}
2005-10-25 19:39:45 +10:00
2005-09-20 23:26:39 +10:00
env_set ( key , val , ENV_EXPORT | ENV_GLOBAL ) ;
}
free ( key ) ;
2005-10-23 20:22:32 +10:00
}
2005-10-25 19:39:45 +10:00
path = env_get ( L " PATH " ) ;
if ( ! path )
{
env_set ( L " PATH " , L " /bin " ARRAY_SEP_STR L " /usr/bin " , ENV_EXPORT | ENV_GLOBAL ) ;
2005-11-04 02:26:25 +10:00
path = env_get ( L " PATH " ) ;
2005-10-25 19:39:45 +10:00
}
else
{
2005-11-04 02:26:25 +10:00
int i , j ;
2005-10-25 19:39:45 +10:00
array_list_t l ;
al_init ( & l ) ;
expand_variable_array ( path , & l ) ;
2005-11-24 04:57:43 +10:00
debug ( 3 , L " PATH is %ls " , path ) ;
2005-10-25 19:39:45 +10:00
2005-11-04 02:26:25 +10:00
const wchar_t * path_el [ ] =
{
L " /bin " ,
L " /usr/bin " ,
PREFIX L " /bin " ,
0
}
;
for ( j = 0 ; path_el [ j ] ; j + + )
2005-10-25 19:39:45 +10:00
{
2005-11-04 02:26:25 +10:00
int has_el = 0 ;
2005-11-24 04:57:43 +10:00
debug ( 3 , L " Check directory %ls " , path_el [ j ] ) ;
2005-11-04 02:26:25 +10:00
for ( i = 0 ; i < al_get_count ( & l ) ; i + + )
2005-10-25 19:39:45 +10:00
{
2005-11-04 02:26:25 +10:00
wchar_t * el = ( wchar_t * ) al_get ( & l , i ) ;
size_t len = wcslen ( el ) ;
while ( ( len > 0 ) & & ( el [ len - 1 ] = = L ' / ' ) )
len - - ;
if ( ( wcslen ( path_el [ j ] ) = = len ) & & ( wcsncmp ( el , path_el [ j ] , len ) = = 0 ) )
{
has_el = 1 ;
}
2005-10-25 19:39:45 +10:00
}
2005-11-04 02:26:25 +10:00
if ( ! has_el )
2005-10-25 19:39:45 +10:00
{
2005-11-04 02:26:25 +10:00
string_buffer_t b ;
2005-11-24 04:57:43 +10:00
debug ( 3 , L " directory %ls was missing " , path_el [ j ] ) ;
2005-11-04 02:26:25 +10:00
sb_init ( & b ) ;
sb_append2 ( & b , path ,
ARRAY_SEP_STR ,
path_el [ j ] ,
( void * ) 0 ) ;
env_set ( L " PATH " , ( wchar_t * ) b . buff , ENV_GLOBAL | ENV_EXPORT ) ;
sb_destroy ( & b ) ;
path = env_get ( L " PATH " ) ;
2005-10-25 19:39:45 +10:00
}
}
2005-11-24 04:57:43 +10:00
debug ( 3 , L " After: PATH is %ls " , path ) ;
2005-10-25 19:39:45 +10:00
al_foreach ( & l , ( void ( * ) ( const void * ) ) & free ) ;
al_destroy ( & l ) ;
}
2005-10-23 20:22:32 +10:00
pw = getpwuid ( getuid ( ) ) ;
2005-10-25 21:03:52 +10:00
if ( pw )
{
uname = str2wcs ( pw - > pw_name ) ;
env_set ( L " USER " , uname , ENV_GLOBAL | ENV_EXPORT ) ;
free ( uname ) ;
}
2005-10-23 20:22:32 +10:00
2005-10-03 23:24:46 +10:00
env_universal_init ( env_get ( L " FISHD_SOKET_DIR " ) ,
env_get ( L " USER " ) ,
2005-10-12 05:23:43 +10:00
& start_fishd ,
& universal_callback ) ;
2005-09-20 23:26:39 +10:00
}
void env_destroy ( )
{
env_universal_destroy ( ) ;
sb_destroy ( & dyn_var ) ;
2005-09-23 06:16:52 +10:00
b_destroy ( & export_buffer ) ;
2005-09-20 23:26:39 +10:00
while ( & top - > env ! = global )
env_pop ( ) ;
hash_destroy ( & env_read_only ) ;
2005-10-25 21:03:52 +10:00
hash_destroy ( & env_electric ) ;
2005-09-20 23:26:39 +10:00
hash_foreach ( global , & clear_hash_entry ) ;
hash_destroy ( global ) ;
free ( top ) ;
2005-09-23 06:16:52 +10:00
free ( export_arr ) ;
2005-09-20 23:26:39 +10:00
}
/**
Find the scope hashtable containing the variable with the specified
key
*/
static env_node_t * env_get_node ( const wchar_t * key )
{
var_entry_t * res ;
env_node_t * env = top ;
while ( env ! = 0 )
{
res = ( var_entry_t * ) hash_get ( & env - > env ,
key ) ;
if ( res ! = 0 )
{
return env ;
}
if ( env - > new_scope )
env = global_env ;
else
env = env - > next ;
}
return 0 ;
}
void env_set ( const wchar_t * key ,
const wchar_t * val ,
int var_mode )
{
int free_val = 0 ;
var_entry_t * entry ;
env_node_t * node ;
int has_changed_old = has_changed ;
int has_changed_new = 0 ;
2005-10-06 08:37:08 +10:00
var_entry_t * e = 0 ;
int done = 0 ;
event_t ev ;
2005-10-12 05:23:43 +10:00
int is_universal = 0 ;
2005-09-20 23:26:39 +10:00
if ( ( var_mode & ENV_USER ) & &
hash_get ( & env_read_only , key ) )
{
return ;
}
if ( wcscmp ( key , L " LANG " ) = = 0 )
{
fish_setlocale ( LC_ALL , val ) ;
}
2005-09-27 00:47:03 +10:00
2005-10-22 20:06:05 +10:00
if ( wcscmp ( key , L " umask " ) = = 0 )
{
wchar_t * end ;
int mask ;
2005-10-23 22:14:29 +10:00
/*
Set the new umask
*/
2005-10-22 20:06:05 +10:00
if ( val & & wcslen ( val ) )
{
errno = 0 ;
mask = wcstol ( val , & end , 8 ) ;
2005-10-23 22:14:29 +10:00
if ( ! errno & & ( ! * end ) & & ( mask < = 0777 ) & & ( mask > = 0 ) )
2005-10-22 20:06:05 +10:00
{
umask ( mask ) ;
}
}
2005-10-23 22:14:29 +10:00
/*
Do not actually create a umask variable , on env_get , it will be calculated dynamically
*/
return ;
2005-10-22 20:06:05 +10:00
}
2005-09-27 00:47:03 +10:00
/*
Zero element arrays are internaly not coded as null but as this placeholder string
*/
2005-10-03 23:24:46 +10:00
if ( ! val & & ( var_mode & ENV_USER ) )
2005-09-27 00:47:03 +10:00
{
val = ENV_NULL ;
}
2005-09-20 23:26:39 +10:00
if ( var_mode & ENV_UNIVERSAL )
{
2005-09-23 06:16:52 +10:00
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 ) ;
2005-10-12 05:23:43 +10:00
is_universal = 1 ;
2005-09-20 23:26:39 +10:00
}
2005-10-06 08:37:08 +10:00
else
2005-09-20 23:26:39 +10:00
{
2005-10-06 08:37:08 +10:00
if ( val = = 0 )
{
wchar_t * prev_val ;
free_val = 1 ;
prev_val = env_get ( key ) ;
val = wcsdup ( prev_val ? prev_val : L " " ) ;
}
2005-09-20 23:26:39 +10:00
2005-10-06 08:37:08 +10:00
node = env_get_node ( key ) ;
if ( node & & & node - > env ! = 0 )
{
e = ( var_entry_t * ) hash_get ( & node - > env ,
key ) ;
2005-09-20 23:26:39 +10:00
2005-10-06 08:37:08 +10:00
if ( e - > export )
has_changed_new = 1 ;
2005-09-20 23:26:39 +10:00
2005-10-06 08:37:08 +10:00
}
2005-09-20 23:26:39 +10:00
2005-10-06 08:37:08 +10:00
if ( ( var_mode & ENV_LOCAL ) | |
( var_mode & ENV_GLOBAL ) )
2005-09-20 23:26:39 +10:00
{
2005-10-06 08:37:08 +10:00
node = ( var_mode & ENV_GLOBAL ) ? global_env : top ;
2005-09-20 23:26:39 +10:00
}
else
{
2005-10-06 08:37:08 +10:00
if ( node )
2005-09-20 23:26:39 +10:00
{
2005-09-23 06:16:52 +10:00
if ( ! ( var_mode & ENV_EXPORT ) & &
! ( var_mode & ENV_UNEXPORT ) )
2005-10-06 08:37:08 +10:00
{
var_mode = e - > export ? ENV_EXPORT : 0 ;
2005-09-23 06:16:52 +10:00
}
2005-09-20 23:26:39 +10:00
}
else
{
2005-10-06 08:37:08 +10:00
if ( ! proc_had_barrier )
2005-11-28 09:22:08 +10:00
{
proc_had_barrier = 1 ;
2005-10-06 08:37:08 +10:00
env_universal_barrier ( ) ;
2005-11-28 09:22:08 +10:00
}
2005-10-06 08:37:08 +10:00
if ( env_universal_get ( key ) )
{
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 ) ;
2005-10-12 05:23:43 +10:00
is_universal = 1 ;
2005-10-06 08:37:08 +10:00
done = 1 ;
2005-09-27 00:54:26 +10:00
2005-10-06 08:37:08 +10:00
}
else
{
/*
New variable with unspecified scope . The default scope is the innermost scope that is shadowing
*/
node = top ;
while ( node - > next & & ! node - > new_scope )
node = node - > next ;
}
2005-09-20 23:26:39 +10:00
}
}
2005-10-06 08:37:08 +10:00
if ( ! done )
{
void * k , * v ;
hash_remove ( & node - > env , key , ( const void * * ) & k , ( const void * * ) & v ) ;
free ( k ) ;
free ( v ) ;
entry = malloc ( sizeof ( var_entry_t ) +
sizeof ( wchar_t ) * ( wcslen ( val ) + 1 ) ) ;
2005-09-20 23:26:39 +10:00
2005-10-06 08:37:08 +10:00
if ( var_mode & ENV_EXPORT )
{
entry - > export = 1 ;
has_changed_new = 1 ;
}
else
entry - > export = 0 ;
2005-09-20 23:26:39 +10:00
2005-10-06 08:37:08 +10:00
wcscpy ( entry - > val , val ) ;
2005-09-20 23:26:39 +10:00
2005-10-06 08:37:08 +10:00
hash_put ( & node - > env , wcsdup ( key ) , entry ) ;
2005-09-20 23:26:39 +10:00
2005-10-06 08:37:08 +10:00
if ( entry - > export )
{
node - > export = 1 ;
}
2005-09-20 23:26:39 +10:00
2005-10-06 08:37:08 +10:00
if ( free_val )
free ( ( void * ) val ) ;
2005-09-20 23:26:39 +10:00
2005-10-06 08:37:08 +10:00
has_changed = has_changed_old | | has_changed_new ;
}
}
2005-09-24 09:15:38 +10:00
2005-10-12 05:23:43 +10:00
if ( ! is_universal )
{
ev . type = EVENT_VARIABLE ;
2005-10-12 05:31:16 +10:00
ev . param1 . variable = key ;
2005-10-12 05:23:43 +10:00
ev . function_name = 0 ;
2005-12-12 08:21:01 +10:00
al_init ( & ev . arguments ) ;
al_push ( & ev . arguments , L " VARIABLE " ) ;
al_push ( & ev . arguments , key ) ;
2005-10-12 05:23:43 +10:00
// debug( 1, L"env_set: fire events on variable %ls", key );
2005-12-12 08:21:01 +10:00
event_fire ( & ev ) ;
2005-10-12 05:23:43 +10:00
// debug( 1, L"env_set: return from event firing" );
2005-12-12 08:21:01 +10:00
al_destroy ( & ev . arguments ) ;
2005-10-12 05:23:43 +10:00
}
2005-10-06 08:37:08 +10:00
2005-09-20 23:26:39 +10:00
}
/**
Attempt to remove / free the specified key / value pair from the
specified hash table .
*/
static int try_remove ( env_node_t * n ,
const wchar_t * key )
{
wchar_t * old_key , * old_val ;
if ( n = = 0 )
return 0 ;
hash_remove ( & n - > env ,
key ,
( const void * * ) & old_key ,
( const void * * ) & old_val ) ;
if ( old_key ! = 0 )
{
var_entry_t * v = ( var_entry_t * ) old_val ;
if ( v - > export )
{
has_changed = 1 ;
}
free ( old_key ) ;
free ( old_val ) ;
return 1 ;
}
if ( n - > new_scope )
return try_remove ( global_env , key ) ;
else
return try_remove ( n - > next , key ) ;
}
void env_remove ( const wchar_t * key , int var_mode )
{
if ( ( var_mode & ENV_USER ) & &
hash_get ( & env_read_only , key ) )
{
return ;
}
if ( ! try_remove ( top , key ) )
{
env_universal_remove ( key ) ;
}
}
wchar_t * env_get ( const wchar_t * key )
{
var_entry_t * res ;
env_node_t * env = top ;
2005-09-27 00:47:03 +10:00
wchar_t * item ;
2005-09-20 23:26:39 +10:00
if ( wcscmp ( key , L " history " ) = = 0 )
{
wchar_t * current ;
int i ;
int add_current = 0 ;
sb_clear ( & dyn_var ) ;
current = reader_get_buffer ( ) ;
if ( current & & wcslen ( current ) )
{
add_current = 1 ;
sb_append ( & dyn_var , current ) ;
}
for ( i = add_current ; i < 8 ; i + + )
{
wchar_t * next = history_get ( i - add_current ) ;
if ( ! next )
{
debug ( 1 , L " No history at idx %d \n " , i ) ;
break ;
}
if ( i ! = 0 )
sb_append ( & dyn_var , ARRAY_SEP_STR ) ;
sb_append ( & dyn_var , next ) ;
}
return ( wchar_t * ) dyn_var . buff ;
}
2005-10-14 21:40:33 +10:00
else if ( wcscmp ( key , L " COLUMNS " ) = = 0 )
{
sb_clear ( & dyn_var ) ;
sb_printf ( & dyn_var , L " %d " , common_get_width ( ) ) ;
return ( wchar_t * ) dyn_var . buff ;
}
else if ( wcscmp ( key , L " LINES " ) = = 0 )
{
sb_clear ( & dyn_var ) ;
sb_printf ( & dyn_var , L " %d " , common_get_height ( ) ) ;
return ( wchar_t * ) dyn_var . buff ;
}
else if ( wcscmp ( key , L " status " ) = = 0 )
{
sb_clear ( & dyn_var ) ;
sb_printf ( & dyn_var , L " %d " , proc_get_last_status ( ) ) ;
return ( wchar_t * ) dyn_var . buff ;
}
2005-10-23 22:14:29 +10:00
else if ( wcscmp ( key , L " umask " ) = = 0 )
{
sb_clear ( & dyn_var ) ;
sb_printf ( & dyn_var , L " 0%0.3o " , get_umask ( ) ) ;
return ( wchar_t * ) dyn_var . buff ;
}
2005-09-20 23:26:39 +10:00
while ( env ! = 0 )
{
res = ( var_entry_t * ) hash_get ( & env - > env ,
2005-10-06 08:37:08 +10:00
key ) ;
2005-09-20 23:26:39 +10:00
if ( res ! = 0 )
{
2005-09-27 00:47:03 +10:00
if ( wcscmp ( res - > val , ENV_NULL ) = = 0 )
{
return 0 ;
}
else
return res - > val ;
2005-09-20 23:26:39 +10:00
}
if ( env - > new_scope )
env = global_env ;
else
env = env - > next ;
}
2005-09-24 09:15:38 +10:00
if ( ! proc_had_barrier )
2005-11-28 09:22:08 +10:00
{
proc_had_barrier = 1 ;
2005-09-24 09:15:38 +10:00
env_universal_barrier ( ) ;
2005-11-28 09:22:08 +10:00
}
2005-09-27 00:47:03 +10:00
item = env_universal_get ( key ) ;
if ( ! item | | ( wcscmp ( item , ENV_NULL ) = = 0 ) )
{
return 0 ;
}
else
return item ;
}
int env_exist ( const wchar_t * key )
{
var_entry_t * res ;
env_node_t * env = top ;
wchar_t * item ;
2005-10-23 22:14:29 +10:00
if ( hash_get ( & env_read_only , key ) | | hash_get ( & env_electric , key ) )
2005-10-14 21:40:33 +10:00
{
return 1 ;
}
2005-09-27 00:47:03 +10:00
while ( env ! = 0 )
{
res = ( var_entry_t * ) hash_get ( & env - > env ,
2005-10-06 08:37:08 +10:00
key ) ;
2005-09-27 00:47:03 +10:00
if ( res ! = 0 )
{
return 1 ;
}
if ( env - > new_scope )
env = global_env ;
else
env = env - > next ;
}
if ( ! proc_had_barrier )
2005-11-28 09:22:08 +10:00
{
proc_had_barrier = 1 ;
2005-09-27 00:47:03 +10:00
env_universal_barrier ( ) ;
2005-11-28 09:22:08 +10:00
}
2005-09-27 00:47:03 +10:00
item = env_universal_get ( key ) ;
return item ! = 0 ;
2005-09-20 23:26:39 +10:00
}
2005-10-25 01:26:25 +10:00
/**
Returns true if the specified scope or any non - shadowed non - global subscopes contain an exported variable .
*/
2005-09-20 23:26:39 +10:00
static int local_scope_exports ( env_node_t * n )
{
if ( n = = global_env )
return 0 ;
if ( n - > export )
return 1 ;
if ( n - > new_scope )
return 0 ;
return local_scope_exports ( n - > next ) ;
}
void env_push ( int new_scope )
{
env_node_t * node = malloc ( sizeof ( env_node_t ) ) ;
node - > next = top ;
node - > export = 0 ;
hash_init ( & node - > env , & hash_wcs_func , & hash_wcs_cmp ) ;
node - > new_scope = new_scope ;
if ( new_scope )
{
2005-09-24 09:15:38 +10:00
has_changed | = local_scope_exports ( top ) ;
2005-09-20 23:26:39 +10:00
}
top = node ;
}
void env_pop ( )
{
if ( & top - > env ! = global )
{
env_node_t * killme = top ;
if ( killme - > new_scope )
{
2005-09-24 09:15:38 +10:00
has_changed | = killme - > export | | local_scope_exports ( killme - > next ) ;
2005-09-20 23:26:39 +10:00
}
top = top - > next ;
hash_foreach ( & killme - > env , & clear_hash_entry ) ;
hash_destroy ( & killme - > env ) ;
free ( killme ) ;
}
else
{
debug ( 0 ,
L " Tried to pop empty environment stack. " ) ;
sanity_lose ( ) ;
}
}
/**
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 ) )
hash_put ( ( hash_table_t * ) aux , key , 0 ) ;
}
2005-09-23 06:16:52 +10:00
2005-10-25 01:26:25 +10:00
/**
Add key to hashtable
*/
2005-09-23 06:16:52 +10:00
static void add_to_hash ( const void * k , void * aux )
2005-09-20 23:26:39 +10:00
{
2005-09-23 06:16:52 +10:00
hash_put ( ( hash_table_t * ) aux ,
k ,
0 ) ;
2005-09-20 23:26:39 +10:00
}
2005-10-25 01:26:25 +10:00
/**
Add key to list
*/
2005-10-23 22:14:29 +10:00
static void add_key_to_list ( const void * key ,
const void * val ,
void * aux )
{
al_push ( ( array_list_t * ) aux , key ) ;
}
2005-09-23 06:16:52 +10:00
2005-09-20 23:26:39 +10:00
void env_get_names ( array_list_t * l , int flags )
{
int show_local = flags & ENV_LOCAL ;
int show_global = flags & ENV_GLOBAL ;
int show_universal = flags & ENV_UNIVERSAL ;
hash_table_t names ;
env_node_t * n = top ;
get_names_show_exported =
flags & ENV_EXPORT | | ( ! ( flags & ENV_UNEXPORT ) ) ;
get_names_show_unexported =
flags & ENV_UNEXPORT | | ( ! ( flags & ENV_EXPORT ) ) ;
if ( ! show_local & & ! show_global & & ! show_universal )
{
show_local = show_universal = show_global = 1 ;
}
hash_init ( & names , & hash_wcs_func , & hash_wcs_cmp ) ;
if ( show_local )
{
while ( n )
{
if ( n = = global_env )
break ;
hash_foreach2 ( & n - > env ,
add_key_to_hash ,
& names ) ;
if ( n - > new_scope )
break ;
else
n = n - > next ;
}
}
if ( show_global )
{
hash_foreach2 ( & global_env - > env ,
add_key_to_hash ,
& names ) ;
2005-10-23 22:14:29 +10:00
2005-09-20 23:26:39 +10:00
if ( get_names_show_unexported )
2005-10-23 22:14:29 +10:00
hash_foreach2 ( & env_electric , & add_key_to_list , l ) ;
2005-10-14 21:40:33 +10:00
if ( get_names_show_exported )
{
al_push ( l , L " COLUMNS " ) ;
al_push ( l , L " LINES " ) ;
}
2005-09-20 23:26:39 +10:00
}
if ( show_universal )
{
2005-09-23 06:16:52 +10:00
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 ) ;
2005-09-20 23:26:39 +10:00
}
hash_get_keys ( & names , l ) ;
hash_destroy ( & names ) ;
}
2005-10-03 23:24:46 +10:00
/**
Function used by env_export_arr to iterate over hashtable of variables
*/
2005-09-23 06:16:52 +10:00
static void export_func1 ( const void * k , const void * v , void * aux )
2005-09-20 23:26:39 +10:00
{
2005-09-23 06:16:52 +10:00
var_entry_t * val_entry = ( var_entry_t * ) v ;
if ( val_entry - > export )
2005-09-20 23:26:39 +10:00
{
2005-09-23 06:16:52 +10:00
hash_table_t * h = ( hash_table_t * ) aux ;
2005-09-20 23:26:39 +10:00
2005-09-23 06:16:52 +10:00
if ( ! hash_get ( h , k ) )
hash_put ( h , k , val_entry - > val ) ;
}
}
2005-09-20 23:26:39 +10:00
2005-10-03 23:24:46 +10:00
/**
Function used by env_export_arr to iterate over hashtable of variables
*/
2005-09-23 06:16:52 +10:00
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 )
{
2005-09-24 09:15:38 +10:00
if ( recalc & & ! proc_had_barrier )
2005-11-28 09:22:08 +10:00
{
proc_had_barrier = 1 ;
2005-09-23 06:16:52 +10:00
env_universal_barrier ( ) ;
2005-11-28 09:22:08 +10:00
}
2005-10-12 05:23:43 +10:00
if ( has_changed )
2005-09-23 06:16:52 +10:00
{
array_list_t uni ;
hash_table_t vals ;
env_node_t * n = top ;
int prev_was_null = 1 ;
int pos = 0 ;
int i ;
2005-09-27 00:47:03 +10:00
debug ( 4 , L " env_export_arr() recalc " ) ;
2005-09-23 06:16:52 +10:00
hash_init ( & vals , & hash_wcs_func , & hash_wcs_cmp ) ;
2005-09-20 23:26:39 +10:00
while ( n )
{
2005-09-23 06:16:52 +10:00
hash_foreach2 ( & n - > env , & export_func1 , & vals ) ;
2005-09-20 23:26:39 +10:00
if ( n - > new_scope )
n = global_env ;
else
2005-09-23 06:16:52 +10:00
n = n - > next ;
2005-09-20 23:26:39 +10:00
}
2005-09-23 06:16:52 +10:00
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 ) ;
}
2005-09-20 23:26:39 +10:00
export_arr [ pos ] = 0 ;
has_changed = 0 ;
2005-09-23 06:16:52 +10:00
2005-09-20 23:26:39 +10:00
}
return export_arr ;
}