From af2d348543f623e30376c54908cfd2eda99fb685 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 30 Jan 2012 21:33:15 -0800 Subject: Substantial modifications of expand_variables to modernize, normalize memory management, adopt C++ types --- common.cpp | 3 +- expand.cpp | 581 ++++++++++++++++++++++++++++--------------------------------- 2 files changed, 267 insertions(+), 317 deletions(-) diff --git a/common.cpp b/common.cpp index 424e97dd..3c535621 100644 --- a/common.cpp +++ b/common.cpp @@ -1820,10 +1820,11 @@ void tokenize_variable_array2( const wcstring &val, std::vector &out) size_t pos = 0, end = val.size(); while (pos < end) { size_t next_pos = val.find(ARRAY_SEP, pos); - if (next_pos == wcstring::npos) next_pos = end; + if (next_pos == wcstring::npos) break; out.push_back(val.substr(pos, next_pos - pos)); pos = next_pos + 1; //skip the separator } + out.push_back(val.substr(pos, end - pos)); } void tokenize_variable_array( const wchar_t *val, array_list_t *out ) diff --git a/expand.cpp b/expand.cpp index 8f400b57..2f892465 100644 --- a/expand.cpp +++ b/expand.cpp @@ -176,7 +176,7 @@ int expand_is_clean( const wchar_t *in ) /** Return the environment variable value for the string starting at \c in. */ -static const wchar_t* expand_var( wchar_t *in ) +static const wchar_t* expand_var(const wchar_t *in) { if( !in ) return 0; @@ -1199,73 +1199,56 @@ static int expand_variables( parser_t &parser, wchar_t *in, array_list_t *out, i return is_ok; } -static int expand_variables2( parser_t &parser, wchar_t * in, std::vector &out, int last_idx ) +static int expand_variables_internal( parser_t &parser, wchar_t * const in, std::vector &out, int last_idx ); + +static int expand_variables2( parser_t &parser, const wcstring &instr, std::vector &out, int last_idx ) { + wchar_t *in = wcsdup(instr.c_str()); + int result = expand_variables_internal(parser, in, out, last_idx); + free(in); + return result; +} + +static int expand_variables_internal( parser_t &parser, wchar_t * const in, std::vector &out, int last_idx ) { - wchar_t c; wchar_t prev_char=0; - int i, j; int is_ok= 1; int empty=0; - static string_buffer_t *var_tmp = 0; - static array_list_t *var_idx_list = 0; - - CHECK( in, 0 ); -// CHECK( out, 0 ); + wcstring var_tmp; + std::vector var_idx_list; + + // CHECK( out, 0 ); - if( !var_tmp ) + for( int i=last_idx; (i>=0) && is_ok && !empty; i-- ) { - var_tmp = sb_halloc( global_context ); - if( !var_tmp ) - DIE_MEM(); - } - else - { - sb_clear(var_tmp ); - } - - if( !var_idx_list ) - { - var_idx_list = al_halloc( global_context ); - if( !var_idx_list ) - DIE_MEM(); - } - else - { - al_truncate( var_idx_list, 0 ); - } - - for( i=last_idx; (i>=0) && is_ok && !empty; i-- ) - { - c = in[i]; + const wchar_t c = in[i]; if( ( c == VARIABLE_EXPAND ) || (c == VARIABLE_EXPAND_SINGLE ) ) { int start_pos = i+1; int stop_pos; - int var_len, new_len; + int var_len; const wchar_t * var_val; - wchar_t * new_in; int is_single = (c==VARIABLE_EXPAND_SINGLE); int var_name_stop_pos; stop_pos = start_pos; - + while( 1 ) { if( !(in[stop_pos ]) ) break; if( !( iswalnum( in[stop_pos] ) || - (wcschr(L"_", in[stop_pos])!= 0) ) ) + (wcschr(L"_", in[stop_pos])!= 0) ) ) break; - + stop_pos++; } var_name_stop_pos = stop_pos; -/* printf( "Stop for '%c'\n", in[stop_pos]);*/ - + /* printf( "Stop for '%c'\n", in[stop_pos]);*/ + var_len = stop_pos - start_pos; - + if( var_len == 0 ) { expand_variable_error( parser, in, stop_pos-1, -1 ); @@ -1273,105 +1256,100 @@ static int expand_variables2( parser_t &parser, wchar_t * in, std::vectorbuff ); - + + var_tmp.append(in + start_pos, var_len); + var_val = expand_var(var_tmp.c_str() ); + if( var_val ) { int all_vars=1; - array_list_t var_item_list; - al_init( &var_item_list ); - + wcstring_list_t var_item_list; + if( in[stop_pos] == L'[' ) { wchar_t *slice_end; all_vars=0; - if( parse_slice( &in[stop_pos], &slice_end, var_idx_list ) ) + if( parse_slice2( in + stop_pos, &slice_end, var_idx_list ) ) { parser.error( SYNTAX_ERROR, - -1, - L"Invalid index value" ); + -1, + L"Invalid index value" ); is_ok = 0; } stop_pos = (slice_end-in); } - + if( is_ok ) { - tokenize_variable_array( var_val, &var_item_list ); + tokenize_variable_array2( var_val, var_item_list ); + if( !all_vars ) { - int j; - for( j=0; j al_get_count( &var_item_list ) ) + Check that we are within array + bounds. If not, truncate the list to + exit. + */ + if( tmp < 1 || (size_t)tmp > var_item_list.size() ) { parser.error( SYNTAX_ERROR, - -1, - ARRAY_BOUNDS_ERR ); + -1, + ARRAY_BOUNDS_ERR ); is_ok=0; - al_truncate( var_idx_list, j ); + var_idx_list.resize(j); break; } else { /* Replace each index in var_idx_list inplace with the string value at the specified index */ - al_set( var_idx_list, j, wcsdup((const wchar_t *)al_get( &var_item_list, tmp-1 ) ) ); + //al_set( var_idx_list, j, wcsdup((const wchar_t *)al_get( &var_item_list, tmp-1 ) ) ); + string_values.at(j) = var_item_list.at(tmp-1); } } - /* Free strings in list var_item_list and truncate it */ - al_foreach( &var_item_list, &free ); - al_truncate( &var_item_list, 0 ); - /* Add items from list idx back to list l */ - al_push_all( &var_item_list, var_idx_list ); + + // string_values is the new var_item_list + var_item_list.swap(string_values); } } - + if( is_ok ) { if( is_single ) { - string_buffer_t res; - in[i]=0; - - sb_init( &res ); - sb_append( &res, in ); - sb_append_char( &res, INTERNAL_SEPARATOR ); - - for( j=0; j1 && new_in[start_pos-2]!=VARIABLE_EXPAND) - { - new_in[start_pos-1]=INTERNAL_SEPARATOR; - new_in[start_pos]=L'\0'; - } - else - new_in[start_pos-1]=L'\0'; - - wcscat( new_in, next ); - wcscat( new_in, &in[stop_pos] ); - - is_ok &= expand_variables2( parser, new_in, out, i ); - } + wcstring new_in; + + if (start_pos > 0) + new_in.append(in, start_pos - 1); + + // at this point new_in.size() is start_pos - 1 + if(start_pos>1 && new_in[start_pos-2]!=VARIABLE_EXPAND) + { + new_in.push_back(INTERNAL_SEPARATOR); + } + new_in.append(next); + new_in.append(in + stop_pos); + is_ok &= expand_variables2( parser, new_in, out, i ); } - free( next ); } } } } - free(in); - al_destroy( &var_item_list ); return is_ok; } else { /* - Expand a non-existing variable - */ + Expand a non-existing variable + */ if( c == VARIABLE_EXPAND ) { /* - Regular expansion, i.e. expand this argument to nothing - */ + Regular expansion, i.e. expand this argument to nothing + */ empty = 1; } else { /* - Expansion to single argument. - */ - string_buffer_t res; - sb_init( &res ); - - in[i]=0; - - sb_append( &res, in ); - sb_append( &res, &in[stop_pos] ); - - is_ok &= expand_variables2( parser, (wchar_t *)res.buff, out, i ); - free(in); + Expansion to single argument. + */ + wcstring res; + in[i] = 0; + res.append(in); + res.append(in + stop_pos); + + is_ok &= expand_variables2( parser, res, out, i ); return is_ok; } } - - + + } - + prev_char = c; } - + if( !empty ) { completion_t data_to_push; data_to_push.completion = in; out.push_back( data_to_push ); } - else - { - free( in ); - } - + return is_ok; } @@ -2059,7 +2014,6 @@ int expand_string2( const wcstring &input, std::vector &output, in std::vector *in, *out; size_t i; - int cmdsubst_ok = 1; int res = EXPAND_OK; if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( input.c_str() ) ) @@ -2069,7 +2023,7 @@ int expand_string2( const wcstring &input, std::vector &output, in output.push_back(data_to_push); return EXPAND_OK; } - + if( EXPAND_SKIP_CMDSUBST & flags ) { wchar_t *begin, *end; @@ -2088,192 +2042,187 @@ int expand_string2( const wcstring &input, std::vector &output, in } else { - cmdsubst_ok = expand_cmdsubst2(parser, input, list1); + int cmdsubst_ok = expand_cmdsubst2(parser, input, list1); + if (! cmdsubst_ok) + return EXPAND_ERROR; } + + in = &list1; + out = &list2; - if( !cmdsubst_ok ) - { - return EXPAND_ERROR; - } - else - { - in = &list1; - out = &list2; + for( i=0; i < in->size(); i++ ) + { + /* + We accept incomplete strings here, since complete uses + expand_string to expand incomplete strings from the + commandline. + */ + int unescape_flags = UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE; + wcstring next = expand_unescape_string( in->at(i).completion, unescape_flags ); - for( i=0; i < in->size(); i++ ) - { - /* - We accept incomplete strings here, since complete uses - expand_string to expand incomplete strings from the - commandline. - */ - int unescape_flags = UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE; - wcstring next = expand_unescape_string( in->at(i).completion, unescape_flags ); - - if( EXPAND_SKIP_VARIABLES & flags ) - { - for (size_t i=0; i < next.size(); i++) { - if (next.at(i) == VARIABLE_EXPAND) { - next[i] = L'$'; - } + if( EXPAND_SKIP_VARIABLES & flags ) + { + for (size_t i=0; i < next.size(); i++) { + if (next.at(i) == VARIABLE_EXPAND) { + next[i] = L'$'; } - completion_t data_to_push; - data_to_push.completion = next; - out->push_back(data_to_push); - } - else - { - if(!expand_variables2( parser, wcsdup(next.c_str()), *out, next.size() - 1 )) - { - return EXPAND_ERROR; - } - } - } + } + completion_t data_to_push; + data_to_push.completion = next; + out->push_back(data_to_push); + } + else + { + if(!expand_variables2( parser, next, *out, next.size() - 1 )) + { + return EXPAND_ERROR; + } + } + } + + in->clear(); + + in = &list2; + out = &list1; + + for( i=0; i < in->size(); i++ ) + { + wcstring next = in->at(i).completion; - in->clear(); + if( !expand_brackets( parser, wcsdup(next.c_str()), flags, *out )) + { + return EXPAND_ERROR; + } + } + in->clear(); + + in = &list1; + out = &list2; + + for( i=0; i < in->size(); i++ ) + { + wcstring next = in->at(i).completion; - in = &list2; - out = &list1; + expand_tilde_internal(next); - for( i=0; i < in->size(); i++ ) - { - wcstring next = in->at(i).completion; - - if( !expand_brackets( parser, wcsdup(next.c_str()), flags, *out )) - { - return EXPAND_ERROR; - } - } - in->clear(); - in = &list1; - out = &list2; + if( flags & ACCEPT_INCOMPLETE ) + { + if( next[0] == PROCESS_EXPAND ) + { + /* + If process expansion matches, we are not + interested in other completions, so we + short-circut and return + */ + expand_pid( next, flags, output ); + return EXPAND_OK; + } + else + { + completion_t data_to_push; + data_to_push.completion = next; + out->push_back(data_to_push); + } + } + else + { + if( !expand_pid( next, flags, *out ) ) + { + return EXPAND_ERROR; + } + } + } + + in->clear(); + + in = &list2; + out = &list1; + + for( i=0; i < in->size(); i++ ) + { + wcstring next_str = in->at(i).completion; + int wc_res; - for( i=0; i < in->size(); i++ ) - { - wcstring next = in->at(i).completion; + remove_internal_separator2( next_str, EXPAND_SKIP_WILDCARDS & flags ); + const wchar_t *next = next_str.c_str(); + + if( ((flags & ACCEPT_INCOMPLETE) && (!(flags & EXPAND_SKIP_WILDCARDS))) || + wildcard_has( next, 1 ) ) + { + const wchar_t *start, *rest; + std::vector *list = out; - expand_tilde_internal(next); + if( next[0] == '/' ) + { + start = L"/"; + rest = &next[1]; + } + else + { + start = L""; + rest = next; + } + if( flags & ACCEPT_INCOMPLETE ) + { + list = &output; + } - if( flags & ACCEPT_INCOMPLETE ) - { - if( next[0] == PROCESS_EXPAND ) - { - /* - If process expansion matches, we are not - interested in other completions, so we - short-circut and return - */ - expand_pid( next, flags, output ); - return EXPAND_OK; - } - else - { - completion_t data_to_push; - data_to_push.completion = next; - out->push_back(data_to_push); - } - } - else - { - if( !expand_pid( next, flags, *out ) ) - { - return EXPAND_ERROR; - } - } - } - - in->clear(); - - in = &list2; - out = &list1; - - for( i=0; i < in->size(); i++ ) - { - wcstring next_str = in->at(i).completion; - int wc_res; - - remove_internal_separator2( next_str, EXPAND_SKIP_WILDCARDS & flags ); - const wchar_t *next = next_str.c_str(); + wc_res = wildcard_expand_string(rest, start, flags, *list); - if( ((flags & ACCEPT_INCOMPLETE) && (!(flags & EXPAND_SKIP_WILDCARDS))) || - wildcard_has( next, 1 ) ) - { - const wchar_t *start, *rest; - std::vector *list = out; - - if( next[0] == '/' ) - { - start = L"/"; - rest = &next[1]; - } - else - { - start = L""; - rest = next; - } - - if( flags & ACCEPT_INCOMPLETE ) - { - list = &output; - } - - wc_res = wildcard_expand_string(rest, start, flags, *list); + if( !(flags & ACCEPT_INCOMPLETE) ) + { - if( !(flags & ACCEPT_INCOMPLETE) ) - { - - switch( wc_res ) - { - case 0: - { - if( !(flags & ACCEPT_INCOMPLETE) ) - { - if( res == EXPAND_OK ) - res = EXPAND_WILDCARD_NO_MATCH; - break; - } - } - - case 1: - { - size_t j; - res = EXPAND_WILDCARD_MATCH; - sort_completions( *out ); - - for( j=0; j< out->size(); j++ ) - { - output.push_back( out->at(j) ); - } - out->clear(); - break; - } - - case -1: - { - return EXPAND_ERROR; - } - - } - } - - } - else - { - if( flags & ACCEPT_INCOMPLETE) - { - } - else - { - completion_t data_to_push; - data_to_push.completion = next; - output.push_back(data_to_push); - } - } + switch( wc_res ) + { + case 0: + { + if( !(flags & ACCEPT_INCOMPLETE) ) + { + if( res == EXPAND_OK ) + res = EXPAND_WILDCARD_NO_MATCH; + break; + } + } + + case 1: + { + size_t j; + res = EXPAND_WILDCARD_MATCH; + sort_completions( *out ); + + for( j=0; j< out->size(); j++ ) + { + output.push_back( out->at(j) ); + } + out->clear(); + break; + } + + case -1: + { + return EXPAND_ERROR; + } + + } + } - } - } + } + else + { + if( flags & ACCEPT_INCOMPLETE) + { + } + else + { + completion_t data_to_push; + data_to_push.completion = next; + output.push_back(data_to_push); + } + } + + } return res; } -- cgit v1.2.3