/** \file builtin_set.c Functions defining the set builtin Functions used for implementing the set builtin. */ #include #include #include #include #include #include #include #include "config.h" #include "util.h" #include "builtin.h" #include "env.h" #include "expand.h" #include "common.h" #include "wgetopt.h" #include "proc.h" #include "parser.h" /** 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) { if (src == 0) { return 0; } while (iswalnum(*src) || *src == L'_') { sb_append_char(name, *src++); } if (*src != L'[' && *src != L'\0') { sb_append(sb_err, L"set: Invalid character in variable name: "); sb_append_char(sb_err, *src); sb_append2(sb_err, L"\n", parser_current_line(), L"\n", 0 ); // builtin_print_help( L"set", sb_err ); return -1; } else { return 0; } } /** Extract indexes from a destination argument of the form name[index1 index2...] */ static int parse_fill_indexes( array_list_t *indexes, const wchar_t *src) { int count = 0; if (src == 0) { return 0; } while (*src != L'\0' && (iswalnum(*src) || *src == L'_')) { src++; } if (*src == L'\0') { return 0; } if (*src++ != L'[') { return -1; } while (iswblank(*src)) { src++; } while (*src != L']') { wchar_t *end; long l_ind = wcstol(src, &end, 10); if (end == src) { wchar_t sbuf[256]; swprintf(sbuf, 255, L"Invalid index starting at %ls\n", src); sb_append(sb_err, sbuf); return -1; } int *ind = (int *) calloc(1, sizeof(int)); *ind = (int) l_ind; al_push(indexes, ind); src = end; count++; while (iswblank(*src)) src++; } return count; } /** Update a list by writing the specified values at the specified indexes */ static int update_values( array_list_t *list, array_list_t *indexes, array_list_t *values ) { int i; //fwprintf(stderr, L"Scan complete\n"); /* 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); if (al_get(list, ind) != 0) { free((void *) al_get(list, ind)); } 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); if (current != 0 && *current == val) { return 1; } } return 0; } /** Erase from a list values at specified indexes */ static int erase_values(array_list_t *list, array_list_t *indexes) { int i; array_list_t result; //fwprintf(stderr, L"Starting with %d\n", al_get_count(list)); 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); //fwprintf(stderr, L"Remaining: %d\n", al_get_count(&result)); return al_get_count(list); } /** Fill a string buffer with values from a list, using ARRAY_SEP_STR to separate them */ static int fill_buffer_from_list(string_buffer_t *sb, array_list_t *list) { int i; for (i = 0; i < al_get_count(list); i++) { wchar_t *v = (wchar_t *) al_get(list, i); if (v != 0) { // fwprintf(stderr, L".\n"); // fwprintf(stderr, L"Collecting %ls from %d\n", v, i); sb_append(sb, v); } if (i < al_get_count(list) - 1) sb_append(sb, ARRAY_SEP_STR); } return al_get_count(list); } /** Print the names of all environment variables in the scope, with or without values, with or without escaping */ static void print_variables(int include_values, int escape, int scope) { array_list_t names; wchar_t **names_arr; int i; al_init( &names ); env_get_names( &names, scope ); sort_list( &names ); for( i = 0; i < al_get_count(&names); i++ ) { wchar_t *key = (wchar_t *)al_get( &names, i ); /* Why does expand_escape free its argument ?! */ wchar_t *e_key = escape ? expand_escape(wcsdup(key), 1) : wcsdup(key); sb_append(sb_out, e_key); if( include_values ) { wchar_t *value = env_get(key); wchar_t *e_value = escape ? expand_escape_variable(value) : wcsdup(value); sb_append2(sb_out, L" ", e_value, 0); free(e_value); } sb_append(sb_out, L"\n"); free(e_key); } al_destroy(&names); } /** The set builtin. Creates, updates and erases environment variables and environemnt variable arrays. */ int builtin_set( wchar_t **argv ) { 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' } , { L"query", no_argument, 0, 'q' } , { 0, 0, 0, 0 } } ; wchar_t short_options[] = L"xglenuUq"; 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; int universal = 0, query=0; /* 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; /* 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; case 'q': query = 1; break; case '?': return 1; default: break; } } if( query && (erase || list || global || local || universal || export || unexport ) ) { sb_append2(sb_err, argv[0], BUILTIN_ERR_COMBO, L"\n", parser_current_line(), L"\n", 0); builtin_print_help( argv[0], sb_err ); return 1; } /* Check operation and modifiers sanity */ if( erase && list ) { sb_append2(sb_err, argv[0], BUILTIN_ERR_COMBO, L"\n", parser_current_line(), L"\n", 0); builtin_print_help( argv[0], sb_err ); return 1; } if( local + global + universal > 1 ) { sb_printf( sb_err, L"%ls%ls\n%ls\n", argv[0], BUILTIN_ERR_GLOCAL, parser_current_line() ); builtin_print_help( argv[0], sb_err ); return 1; } if( export && unexport ) { sb_append2(sb_err, argv[0], BUILTIN_ERR_EXPUNEXP, L"\n", parser_current_line(), L"\n", 0); builtin_print_help( argv[0], sb_err ); return 1; } if( query ) { /* Query mode. Return number of specified variables that do not exist. */ int i; for( i=woptind; i