diff options
author | 2006-05-10 02:40:55 +1000 | |
---|---|---|
committer | 2006-05-10 02:40:55 +1000 | |
commit | 06668bfacbc934598a1bc6ed25f6c1dcb5070064 (patch) | |
tree | a5a8c2be01675ae726fbb40a903d815171094455 /builtin_set.c | |
parent | df59b8498ffcc4738b60bd9112fbe2f22b103504 (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.c | 564 |
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; + } |