aboutsummaryrefslogtreecommitdiffhomepage
path: root/builtin_set.c
diff options
context:
space:
mode:
authorGravatar axel <axel@liljencrantz.se>2006-05-10 02:40:55 +1000
committerGravatar axel <axel@liljencrantz.se>2006-05-10 02:40:55 +1000
commit06668bfacbc934598a1bc6ed25f6c1dcb5070064 (patch)
treea5a8c2be01675ae726fbb40a903d815171094455 /builtin_set.c
parentdf59b8498ffcc4738b60bd9112fbe2f22b103504 (diff)
Alter syntax for set builtin so that better slicing operations are possible
darcs-hash:20060509164055-ac50b-8514b73bb9e992c463966f95f783f01893ba93bd.gz
Diffstat (limited to 'builtin_set.c')
-rw-r--r--builtin_set.c564
1 files changed, 289 insertions, 275 deletions
diff --git a/builtin_set.c b/builtin_set.c
index ab6e7e6a..5849c785 100644
--- a/builtin_set.c
+++ b/builtin_set.c
@@ -28,64 +28,147 @@ Functions used for implementing the set builtin.
#define BUILTIN_SET_PATH_ERROR L"%ls: Could not add component %ls to %ls.\n"
#define BUILTIN_SET_PATH_HINT L"%ls: Did you mean 'set %ls $%ls %ls'?\n"
+#define BUILTIN_SET_ARG_COUNT L"%ls: The number of variable indexes does not match the number of values\n"
+
+static int is_path_variable( const wchar_t *env )
+{
+ return contains_str( env,
+ L"PATH",
+ L"CDPATH",
+ (void *)0 );
+}
/**
- Call env_set. On error, print a description of the problem to
- stderr.
+ 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.
*/
-static void my_env_set( const wchar_t *key, const wchar_t *val, int scope )
+static int my_env_set( const wchar_t *key, array_list_t *val, int scope )
{
-
- switch( env_set( key, val, scope | ENV_USER ) )
+ string_buffer_t sb;
+ int i;
+ int retcode = 0;
+ wchar_t *val_str=0;
+
+ if( is_path_variable( key ) )
{
- case ENV_PERM:
+ int error = 0;
+
+ for( i=0; i<al_get_count( val ); i++ )
{
- sb_printf( sb_err, _(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key );
- break;
+ 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 );
+ 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;
}
+
}
-}
-/**
- Extract the name from a destination argument of the form name[index1 index2...]
-*/
-static int parse_fill_name( string_buffer_t *name,
- const wchar_t *src)
-{
+ sb_init( &sb );
- if (src == 0)
+ if( al_get_count( val ) )
{
- return 0;
+ 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;
+
}
- while (iswalnum(*src) || *src == L'_')
+ switch( env_set( key, val_str, scope | ENV_USER ) )
{
- sb_append_char(name, *src++);
+ case ENV_PERM:
+ {
+ sb_printf( sb_err, _(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key );
+ retcode=1;
+ break;
+ }
}
-
- if (*src != L'[' && *src != L'\0')
- {
- sb_printf( sb_err, BUILTIN_ERR_VARCHAR, L"set", *src );
- sb_append2(sb_err, parser_current_line(), L"\n", (void *)0 );
-// builtin_print_help( L"set", sb_err );
- return -1;
- }
- else
- {
- return 0;
- }
-}
+ sb_destroy( &sb );
+ return retcode;
+}
/**
Extract indexes from a destination argument of the form name[index1 index2...]
+
+ \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
*/
-static int parse_fill_indexes( array_list_t *indexes,
- const wchar_t *src)
+static int parse_index( array_list_t *indexes,
+ const wchar_t *src,
+ const wchar_t *name )
{
+ int len;
+
int count = 0;
-
+ const wchar_t *src_orig = src;
+
if (src == 0)
{
return 0;
@@ -96,16 +179,27 @@ static int parse_fill_indexes( array_list_t *indexes,
src++;
}
- if (*src == L'\0')
+ if (*src != L'[')
{
+ sb_printf( sb_err, _(BUILTIN_SET_ARG_COUNT), L"set" );
return 0;
}
+
+ len = src-src_orig;
- if (*src++ != L'[')
+ if( (wcsncmp( src_orig, name, len )!=0) || (wcslen(name) != (len)) )
{
- return -1;
+ 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++;
@@ -118,9 +212,9 @@ static int parse_fill_indexes( array_list_t *indexes,
if (end == src)
{
sb_printf(sb_err, _(L"%ls: Invalid index starting at '%ls'\n"), L"set", src);
- return -1;
+ return 0;
}
-
+
int *ind = (int *) calloc(1, sizeof(int));
*ind = (int) l_ind;
al_push(indexes, ind);
@@ -185,7 +279,7 @@ static int al_contains_int( array_list_t *list,
/**
Erase from a list values at specified indexes
*/
-static int erase_values(array_list_t *list, array_list_t *indexes)
+static void erase_values(array_list_t *list, array_list_t *indexes)
{
int i;
array_list_t result;
@@ -207,8 +301,6 @@ static int erase_values(array_list_t *list, array_list_t *indexes)
al_truncate(list,0);
al_push_all( list, &result );
al_destroy(&result);
-
- return al_get_count(list);
}
@@ -269,13 +361,6 @@ static void print_variables(int include_values, int esc, int scope)
al_destroy(&names);
}
-static int is_path_variable( const wchar_t *env )
-{
- return contains_str( env,
- L"PATH",
- L"CDPATH",
- (void *)0 );
-}
/**
@@ -337,14 +422,12 @@ int builtin_set( wchar_t **argv )
Variables used for performing the actual work
*/
wchar_t *dest = 0;
- array_list_t values;
- string_buffer_t name_sb;
int retcode=0;
- wchar_t *name;
- array_list_t indexes;
- int retval;
-
-
+ int scope;
+ int slice=0;
+ int i;
+
+
/* Parse options to obtain the requested operation and the modifiers */
woptind = 0;
while (1)
@@ -407,7 +490,7 @@ int builtin_set( wchar_t **argv )
argv[0],
parser_current_line() );
- builtin_print_help( argv[0], sb_err );
+// builtin_print_help( argv[0], sb_err );
return 1;
}
@@ -420,7 +503,7 @@ int builtin_set( wchar_t **argv )
argv[0],
parser_current_line() );
- builtin_print_help( argv[0], sb_err );
+// builtin_print_help( argv[0], sb_err );
return 1;
}
@@ -433,7 +516,7 @@ int builtin_set( wchar_t **argv )
BUILTIN_ERR_GLOCAL,
argv[0],
parser_current_line() );
- builtin_print_help( argv[0], sb_err );
+// builtin_print_help( argv[0], sb_err );
return 1;
}
@@ -446,10 +529,15 @@ int builtin_set( wchar_t **argv )
BUILTIN_ERR_EXPUNEXP,
argv[0],
parser_current_line() );
- builtin_print_help( argv[0], sb_err );
+// builtin_print_help( argv[0], sb_err );
return 1;
}
+ /*
+ 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;
+
if( query )
{
/*
@@ -468,262 +556,188 @@ int builtin_set( wchar_t **argv )
return retcode;
}
-
- /* Parse destination */
- if( woptind < argc )
+ if( woptind == argc )
{
- dest = wcsdup(argv[woptind++]);
-
- if( !wcslen( dest ) )
+ /*
+ Print values of variables
+ */
+
+ if( erase )
{
- free( dest );
- sb_printf( sb_err, BUILTIN_ERR_VARNAME_ZERO, argv[0] );
- return 1;
- }
+ 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;
}
- /* Parse values */
- // wchar_t **values = woptind < argc ? (wchar_t **) calloc(argc - woptind, sizeof(wchar_t *)) : 0;
+ 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();
+ }
- al_init(&values);
- while( woptind < argc )
+ if( wcschr( dest, L'[' ) )
{
- al_push(&values, argv[woptind++]);
+ slice = 1;
+ *wcschr( dest, L'[' )=0;
+ }
+
+ if( !wcslen( dest ) )
+ {
+ free( dest );
+ sb_printf( sb_err, BUILTIN_ERR_VARNAME_ZERO, argv[0] );
+ return 1;
}
- if( dest && is_path_variable( dest ) )
+
+ /*
+ set assignment can work in two modes, either using slices or
+ using the whole array. We detect which mode is used here.
+ */
+
+ if( slice )
{
- int i;
- int error = 0;
-
- for( i=0; i<al_get_count( &values ); i++ )
- {
- int show_perror = 0;
- int show_hint = 0;
-
- struct stat buff;
- wchar_t *dir = (wchar_t *)al_get( &values, i );
-
- if( wstat( dir, &buff ) )
- {
- error = 1;
- show_perror = 1;
- }
- if( !( S_IFDIR & buff.st_mode ) )
+ /*
+ 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 ) )
{
- error = 1;
-
+ retcode = 1;
+ break;
}
- if( error )
+ val_count = argc-woptind-1;
+ idx_count = al_get_count( &indexes );
+
+ if( !erase )
{
- wchar_t *colon;
-
- sb_printf( sb_err,
- _(BUILTIN_SET_PATH_ERROR),
- argv[0],
- dir,
- dest );
- colon = wcschr( dir, L':' );
-
- if( colon && *(colon+1) )
+ if( val_count < idx_count )
{
- show_hint = 1;
+ sb_printf( sb_err, _(BUILTIN_SET_ARG_COUNT), argv[0] );
+ retcode=1;
+ break;
+ }
+ if( val_count == idx_count )
+ {
+ woptind++;
+ break;
}
-
- }
-
- if( show_perror )
- {
- builtin_wperror( argv[0] );
- }
-
- if( show_hint )
- {
- sb_printf( sb_err,
- _(BUILTIN_SET_PATH_HINT),
- argv[0],
- dest,
- dest,
- wcschr( dir, L':' )+1);
- }
-
- if( error )
- {
- break;
}
-
- }
+ }
- if( error )
+ if( !retcode )
{
- al_destroy(&values);
- return 1;
- }
-
- }
+ /*
+ Slice indexes have been calculated, do the actual work
+ */
+ array_list_t result;
+ al_init(&result);
- /* Extract variable name and indexes */
+ 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);
- sb_init(&name_sb);
- retval = parse_fill_name(&name_sb, dest);
+ while( woptind < argc )
+ {
+ al_push(&value, argv[woptind++]);
+ }
-
- if( retval < 0 )
- retcode=1;
+ update_values( &result,
+ &indexes,
+ &value );
+
+ my_env_set(dest,
+ &result,
+ scope);
+
+ al_destroy( &value );
+
+ }
+ al_foreach( &result, (void (*)(const void *))&free );
+ al_destroy( &result );
+ }
- if( !retcode )
- {
- name = (wchar_t *) name_sb.buff;
+ al_foreach( &indexes, (void (*)(const void *))&free );
+ al_destroy(&indexes);
+ al_destroy(&values);
- al_init(&indexes);
- retval = parse_fill_indexes(&indexes, dest);
- if (retval < 0)
- retcode = 1;
}
-
- if( !retcode )
+ else
{
+ woptind++;
- int i;
- int finished=0;
-
- /* Do the actual work */
- int scope = (local ? ENV_LOCAL : 0) | (global ? ENV_GLOBAL : 0) | (export ? ENV_EXPORT : 0) | (unexport ? ENV_UNEXPORT : 0) | (universal ? ENV_UNIVERSAL:0) | ENV_USER;
- if( list )
- {
- /* Maybe we should issue an error if there are any other arguments? */
- print_variables(0, 0, scope);
- finished=1;
- }
-
- if( (!finished ) &&
- (name == 0 || wcslen(name) == 0))
+ /*
+ No slicing
+ */
+ if( erase )
{
- /* No arguments -- display name & value for all variables in scope */
- if( erase )
+ if( woptind != argc )
{
- sb_printf( sb_err,
- _(L"%ls: Erase needs a variable name\n%ls\n"),
+ sb_printf( sb_err,
+ _(L"%ls: Values cannot be specfied with erase\n%ls\n"),
argv[0],
parser_current_line() );
-
- builtin_print_help( argv[0], sb_err );
- retcode = 1;
+ retcode=1;
}
- else
- {
- print_variables( 1, 1, scope );
- }
-
- finished=1;
- }
-
-
- if( !finished )
- {
- if( al_get_count( &values ) == 0 &&
- al_get_count( &indexes ) == 0 &&
- !erase &&
- !list )
+ else
{
- my_env_set( name, 0, scope );
- finished = 1;
+ env_remove( dest, ENV_USER );
}
}
-
- if( !finished )
+ else
{
- /* There are some arguments, we have at least a variable name */
- if( erase && al_get_count(&values) != 0 )
+ array_list_t val;
+ al_init( &val );
+
+ for( i=woptind; i<argc; i++ )
{
- sb_printf( sb_err,
- _(L"%ls: Values cannot be specfied with erase\n%ls\n"),
- argv[0],
- parser_current_line() );
-
- builtin_print_help( argv[0], sb_err );
- retcode = 1;
- }
- else
- {
- /* All ok, we can alter the specified variable */
- array_list_t val_l;
- al_init(&val_l);
-
- void *old=0;
-
- if (al_get_count(&indexes) == 0)
- {
- /* We will act upon the entire variable */
-
- al_push( &val_l, wcsdup(L"") );
- old = val_l.arr;
-
- /* Build indexes for all variable or all new values */
- int end_index = erase ? al_get_count(&val_l) : al_get_count(&values);
- for (i = 0; i < end_index; i++)
- {
- int *ind = (int *) calloc(1, sizeof(int));
- *ind = i + 1;
- al_push(&indexes, ind);
- }
- }
- else
- {
- /* We will act upon some specific indexes */
- expand_variable_array( env_get(name), &val_l );
- }
-
- string_buffer_t result_sb;
- sb_init(&result_sb);
- if (erase)
- {
- int rem = erase_values(&val_l, &indexes);
- if (rem == 0)
- {
- env_remove(name, ENV_USER);
- }
- else
- {
- fill_buffer_from_list(&result_sb, &val_l);
-
- my_env_set(name, (wchar_t *) result_sb.buff, scope);
- }
- }
- else
- {
-
- update_values( &val_l,
- &indexes,
- &values );
-
- fill_buffer_from_list( &result_sb,
- &val_l );
-
- my_env_set(name,
- (wchar_t *) result_sb.buff,
- scope);
- }
-
- al_foreach( &val_l, (void (*)(const void *))&free );
- al_destroy(&val_l);
- sb_destroy(&result_sb);
+ al_push( &val, argv[i] );
}
- }
- al_foreach( &indexes, (void (*)(const void *))&free );
- al_destroy(&indexes);
+ retcode = my_env_set( dest, &val, scope );
+
+ al_destroy( &val );
+
+ }
}
-/* Common cleanup */
-
- free(dest);
- sb_destroy(&name_sb);
- al_destroy( &values );
+ free( dest );
return retcode;
+
}