Merge branch 'index_range'

This commit is contained in:
ridiculousfish 2012-07-19 10:59:11 -07:00
commit bb4a05032b
7 changed files with 105 additions and 24 deletions

View file

@ -238,9 +238,31 @@ static int parse_index( std::vector<long> &indexes,
l_ind = var_count+l_ind+1; l_ind = var_count+l_ind+1;
} }
indexes.push_back( l_ind );
src = end; src = end;
if ( *src==L'.' && *(src+1)==L'.' ){
src+=2;
long l_ind2 = wcstol( src, &end, 10 );
if( end==src || errno )
{
return 1;
}
src = end;
if( l_ind2 < 0 )
{
l_ind2 = var_count+l_ind2+1;
}
int direction = l_ind2<l_ind ? -1 : 1 ;
for (long jjj = l_ind; jjj*direction <= l_ind2*direction; jjj+=direction) {
// debug(0, L"Expand range [set]: %i\n", jjj);
indexes.push_back( jjj );
count++; count++;
}
}
else {
indexes.push_back( l_ind );
count++;
}
while (iswspace(*src)) src++; while (iswspace(*src)) src++;
} }

View file

@ -875,17 +875,14 @@ void expand_variable_error( parser_t &parser, const wchar_t *token, int token_po
/** /**
Parse an array slicing specification Parse an array slicing specification
*/ */
static int parse_slice( const wchar_t *in, wchar_t **end_ptr, std::vector<long> &idx ) static int parse_slice( const wchar_t *in, wchar_t **end_ptr, std::vector<long> &idx, int size )
{ {
wchar_t *end; wchar_t *end;
int pos = 1; int pos = 1;
// debug( 0, L"parse_slice on '%ls'", in ); // debug( 0, L"parse_slice on '%ls'", in );
while( 1 ) while( 1 )
{ {
long tmp; long tmp;
@ -907,8 +904,34 @@ static int parse_slice( const wchar_t *in, wchar_t **end_ptr, std::vector<long>
} }
// debug( 0, L"Push idx %d", tmp ); // debug( 0, L"Push idx %d", tmp );
idx.push_back(tmp); long i1 = tmp>-1 ? tmp : size+tmp+1;
pos = end-in; pos = end-in;
while( in[pos]==INTERNAL_SEPARATOR )
pos++;
if ( in[pos]==L'.' && in[pos+1]==L'.' ){
pos+=2;
while( in[pos]==INTERNAL_SEPARATOR )
pos++;
long tmp1 = wcstol( &in[pos], &end, 10 );
if( ( errno ) || ( end == &in[pos] ) )
{
return 1;
}
pos = end-in;
// debug( 0, L"Push range %d %d", tmp, tmp1 );
long i2 = tmp1>-1 ? tmp1 : size+tmp1+1;
// debug( 0, L"Push range idx %d %d", i1, i2 );
short direction = i2<i1 ? -1 : 1 ;
for (long jjj = i1; jjj*direction <= i2*direction; jjj+=direction) {
// debug(0, L"Expand range [subst]: %i\n", jjj);
idx.push_back( jjj );
}
continue;
}
// debug( 0, L"Push idx %d", tmp );
idx.push_back( i1 );
} }
if( end_ptr ) if( end_ptr )
@ -1000,25 +1023,26 @@ static int expand_variables_internal( parser_t &parser, wchar_t * const in, std:
int all_vars=1; int all_vars=1;
wcstring_list_t var_item_list; wcstring_list_t var_item_list;
if( is_ok )
{
tokenize_variable_array( var_val.c_str(), var_item_list );
if( in[stop_pos] == L'[' ) if( in[stop_pos] == L'[' )
{ {
wchar_t *slice_end; wchar_t *slice_end;
all_vars=0; all_vars=0;
if( parse_slice( in + stop_pos, &slice_end, var_idx_list ) ) if( parse_slice( in + stop_pos, &slice_end, var_idx_list, var_item_list.size() ) )
{ {
parser.error( SYNTAX_ERROR, parser.error( SYNTAX_ERROR,
-1, -1,
L"Invalid index value" ); L"Invalid index value" );
is_ok = 0; is_ok = 0;
break;
} }
stop_pos = (slice_end-in); stop_pos = (slice_end-in);
} }
if( is_ok )
{
tokenize_variable_array( var_val.c_str(), var_item_list );
if( !all_vars ) if( !all_vars )
{ {
wcstring_list_t string_values(var_idx_list.size()); wcstring_list_t string_values(var_idx_list.size());
@ -1026,11 +1050,6 @@ static int expand_variables_internal( parser_t &parser, wchar_t * const in, std:
for( size_t j=0; j<var_idx_list.size(); j++) for( size_t j=0; j<var_idx_list.size(); j++)
{ {
long tmp = var_idx_list.at(j); long tmp = var_idx_list.at(j);
if( tmp < 0 )
{
tmp = ((long)var_item_list.size())+tmp+1;
}
/* /*
Check that we are within array Check that we are within array
bounds. If not, truncate the list to bounds. If not, truncate the list to
@ -1335,7 +1354,7 @@ static int expand_cmdsubst( parser_t &parser, const wcstring &input, std::vector
std::vector<long> slice_idx; std::vector<long> slice_idx;
wchar_t *slice_end; wchar_t *slice_end;
if( parse_slice( tail_begin, &slice_end, slice_idx ) ) if( parse_slice( tail_begin, &slice_end, slice_idx, sub_res.size() ) )
{ {
parser.error( SYNTAX_ERROR, -1, L"Invalid index value" ); parser.error( SYNTAX_ERROR, -1, L"Invalid index value" );
return 0; return 0;
@ -1347,17 +1366,13 @@ static int expand_cmdsubst( parser_t &parser, const wcstring &input, std::vector
for( i=0; i < slice_idx.size(); i++ ) for( i=0; i < slice_idx.size(); i++ )
{ {
long idx = slice_idx.at(i); long idx = slice_idx.at(i);
if( idx < 0 )
{
idx = sub_res.size() + idx + 1;
}
if( idx < 1 || (size_t)idx > sub_res.size() ) if( idx < 1 || (size_t)idx > sub_res.size() )
{ {
parser.error( SYNTAX_ERROR, -1, L"Invalid index value" ); parser.error( SYNTAX_ERROR,
-1,
ARRAY_BOUNDS_ERR );
return 0; return 0;
} }
idx = idx-1; idx = idx-1;
sub_res2.push_back(sub_res.at(idx)); sub_res2.push_back(sub_res.at(idx));

0
tests/test8.err Normal file
View file

25
tests/test8.in Normal file
View file

@ -0,0 +1,25 @@
# Test index ranges
echo Test variable expand
set n 10
set test (seq $n)
echo $test[1..$n] # normal range
echo $test[$n..1] # inverted range
echo $test[2..5 8..6] # several ranges
echo $test[-1..-2] # range with negative limits
echo $test[-1..1] # range with mixed limits
echo Test variable set
set test1 $test
set test1[-1..1] $test; echo $test1
set test1[1..$n] $test; echo $test1
set test1[$n..1] $test; echo $test1
set test1[2..4 -2..-4] $test1[4..2 -4..-2]; echo $test1
echo Test command substitution
echo (seq 5)[-1..1]
echo (seq $n)[3..5 -2..2]
echo Test more
echo $test[(count $test)..1]
echo $test[1..(count $test)]

17
tests/test8.out Normal file
View file

@ -0,0 +1,17 @@
Test variable expand
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
2 3 4 5 8 7 6
10 9
10 9 8 7 6 5 4 3 2 1
Test variable set
10 9 8 7 6 5 4 3 2 1
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
10 7 8 9 6 5 2 3 4 1
Test command substitution
5 4 3 2 1
3 4 5 9 8 7 6 5 4 3 2
Test more
10 9 8 7 6 5 4 3 2 1
1 2 3 4 5 6 7 8 9 10

1
tests/test8.status Normal file
View file

@ -0,0 +1 @@
0

View file

@ -6,3 +6,4 @@ File test4.in tested ok
File test5.in tested ok File test5.in tested ok
File test6.in tested ok File test6.in tested ok
File test7.in tested ok File test7.in tested ok
File test8.in tested ok