mirror of
https://github.com/transmission/transmission
synced 2024-12-24 00:34:04 +00:00
(trunk libT) #1671: transmission-remote --get option not including all files
This commit is contained in:
parent
c08f370e8a
commit
65bba3fdfb
4 changed files with 191 additions and 59 deletions
|
@ -1040,29 +1040,6 @@ tr_rpc_request_exec_json( tr_session * session,
|
|||
tr_bencFree( &top );
|
||||
}
|
||||
|
||||
static void
|
||||
addToken( tr_benc * list,
|
||||
const char * token,
|
||||
size_t len )
|
||||
{
|
||||
char * p;
|
||||
const char * end = token + len;
|
||||
const long a = strtol( token, &p, 10 );
|
||||
|
||||
if( p == end )
|
||||
tr_bencListAddInt( list, a );
|
||||
else if( *p == '-' && isdigit( p[1] ) )
|
||||
{
|
||||
const long b = strtol( p + 1, &p, 10 );
|
||||
if( ( p == end ) && ( b > a ) )
|
||||
{
|
||||
long i;
|
||||
for( i = a; i <= b; ++i )
|
||||
tr_bencListAddInt( list, i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Munge the URI into a usable form.
|
||||
*
|
||||
|
@ -1074,49 +1051,25 @@ addToken( tr_benc * list,
|
|||
*/
|
||||
void
|
||||
tr_rpc_parse_list_str( tr_benc * setme,
|
||||
const char * str_in,
|
||||
const char * str,
|
||||
int len )
|
||||
|
||||
{
|
||||
char * str = tr_strndup( str_in, len );
|
||||
int isNum;
|
||||
int isNumList;
|
||||
int commaCount;
|
||||
const char * walk;
|
||||
int valueCount;
|
||||
int * values = tr_parseNumberRange( str, len, &valueCount );
|
||||
|
||||
isNum = 1;
|
||||
isNumList = 1;
|
||||
commaCount = 0;
|
||||
walk = str;
|
||||
for( ; *walk && ( isNumList || isNum ); ++walk )
|
||||
{
|
||||
if( isNumList ) isNumList = *walk == '-' || isdigit( *walk )
|
||||
|| *walk == ',';
|
||||
if( isNum ) isNum = *walk == '-' || isdigit( *walk );
|
||||
if( *walk == ',' ) ++commaCount;
|
||||
}
|
||||
|
||||
if( isNum )
|
||||
tr_bencInitInt( setme, strtol( str, NULL, 10 ) );
|
||||
else if( !isNumList )
|
||||
if( valueCount == 0 )
|
||||
tr_bencInitStr( setme, str, len );
|
||||
else
|
||||
{
|
||||
tr_bencInitList( setme, commaCount + 1 );
|
||||
walk = str;
|
||||
while( *walk )
|
||||
{
|
||||
const char * p = strchr( walk, ',' );
|
||||
if( !p )
|
||||
p = walk + strlen( walk );
|
||||
addToken( setme, walk, p - walk );
|
||||
if( *p != ',' )
|
||||
break;
|
||||
walk = p + 1;
|
||||
}
|
||||
else if( valueCount == 1 )
|
||||
tr_bencInitInt( setme, values[0] );
|
||||
else {
|
||||
int i;
|
||||
tr_bencInitList( setme, valueCount );
|
||||
for( i=0; i<valueCount; ++i )
|
||||
tr_bencListAddInt( setme, values[i] );
|
||||
}
|
||||
|
||||
tr_free( str );
|
||||
tr_free( values );
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -185,6 +185,46 @@ test_utf8( void )
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
test_numbers( void )
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
int * numbers;
|
||||
|
||||
numbers = tr_parseNumberRange( "1-10,13,16-19", -1, &count );
|
||||
check( count == 15 );
|
||||
check( numbers != NULL );
|
||||
check( numbers[0] == 1 );
|
||||
check( numbers[5] == 6 );
|
||||
check( numbers[9] == 10 );
|
||||
check( numbers[10] == 13 );
|
||||
check( numbers[11] == 16 );
|
||||
check( numbers[14] == 19 );
|
||||
tr_free( numbers );
|
||||
|
||||
numbers = tr_parseNumberRange( "1-5,3-7,2-6", -1, &count );
|
||||
check( count == 7 );
|
||||
check( numbers != NULL );
|
||||
for( i=0; i<count; ++i )
|
||||
check( numbers[i] == i+1 );
|
||||
tr_free( numbers );
|
||||
|
||||
numbers = tr_parseNumberRange( "1-Hello", -1, &count );
|
||||
check( count == 0 );
|
||||
check( numbers == NULL );
|
||||
|
||||
numbers = tr_parseNumberRange( "1-", -1, &count );
|
||||
check( count == 0 );
|
||||
check( numbers == NULL );
|
||||
|
||||
numbers = tr_parseNumberRange( "Hello", -1, &count );
|
||||
check( count == 0 );
|
||||
check( numbers == NULL );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main( void )
|
||||
{
|
||||
|
@ -211,6 +251,8 @@ main( void )
|
|||
return i;
|
||||
if( ( i = test_utf8( ) ) )
|
||||
return i;
|
||||
if( ( i = test_numbers( ) ) )
|
||||
return i;
|
||||
|
||||
/* test that tr_cryptoRandInt() stays in-bounds */
|
||||
for( i = 0; i < 100000; ++i )
|
||||
|
|
|
@ -1378,3 +1378,138 @@ tr_utf8clean( const char * str, int max_len, tr_bool * err )
|
|||
evbuffer_free( buf );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
struct number_range
|
||||
{
|
||||
int low;
|
||||
int high;
|
||||
};
|
||||
|
||||
/**
|
||||
* This should be a single number (ex. "6") or a range (ex. "6-9").
|
||||
* Anything else is an error and will return failure.
|
||||
*/
|
||||
static tr_bool
|
||||
parseNumberSection( const char * str, int len, struct number_range * setme )
|
||||
{
|
||||
long a, b;
|
||||
tr_bool success;
|
||||
char * end;
|
||||
const int error = errno;
|
||||
char * tmp = tr_strndup( str, len );
|
||||
|
||||
errno = 0;
|
||||
a = strtol( tmp, &end, 10 );
|
||||
if( errno || ( end == tmp ) ) {
|
||||
success = FALSE;
|
||||
} else if( *end != '-' ) {
|
||||
b = a;
|
||||
success = TRUE;
|
||||
} else {
|
||||
const char * pch = end + 1;
|
||||
b = strtol( pch, &end, 10 );
|
||||
if( errno || ( pch == end ) )
|
||||
success = FALSE;
|
||||
else if( *end ) /* trailing data */
|
||||
success = FALSE;
|
||||
else
|
||||
success = TRUE;
|
||||
}
|
||||
tr_free( tmp );
|
||||
|
||||
setme->low = MIN( a, b );
|
||||
setme->high = MAX( a, b );
|
||||
|
||||
errno = error;
|
||||
return success;
|
||||
}
|
||||
|
||||
static int
|
||||
compareInt( const void * va, const void * vb )
|
||||
{
|
||||
const int a = *(const int *)va;
|
||||
const int b = *(const int *)vb;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a string like "1-4" or "1-4,6,9,14-51", this allocates and returns an
|
||||
* array of setmeCount ints of all the values in the array.
|
||||
* For example, "5-8" will return [ 5, 6, 7, 8 ] and setmeCount will be 4.
|
||||
* It's the caller's responsibility to call tr_free() on the returned array.
|
||||
* If a fragment of the string can't be parsed, NULL is returned.
|
||||
*/
|
||||
int*
|
||||
tr_parseNumberRange( const char * str_in, int len, int * setmeCount )
|
||||
{
|
||||
int n = 0;
|
||||
int * uniq = NULL;
|
||||
char * str = tr_strndup( str_in, len );
|
||||
const char * walk;
|
||||
tr_list * ranges = NULL;
|
||||
tr_bool success = TRUE;
|
||||
|
||||
walk = str;
|
||||
while( walk && *walk && success ) {
|
||||
struct number_range range;
|
||||
const char * pch = strchr( walk, ',' );
|
||||
if( pch ) {
|
||||
success = parseNumberSection( walk, pch-walk, &range );
|
||||
walk = pch + 1;
|
||||
} else {
|
||||
success = parseNumberSection( walk, strlen( walk ), &range );
|
||||
walk += strlen( walk );
|
||||
}
|
||||
if( success )
|
||||
tr_list_append( &ranges, tr_memdup( &range, sizeof( struct number_range ) ) );
|
||||
}
|
||||
|
||||
if( !success )
|
||||
{
|
||||
*setmeCount = 0;
|
||||
uniq = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
int n2;
|
||||
tr_list * l;
|
||||
int * sorted = NULL;
|
||||
|
||||
/* build a sorted number array */
|
||||
n = n2 = 0;
|
||||
for( l=ranges; l!=NULL; l=l->next ) {
|
||||
const struct number_range * r = l->data;
|
||||
n += r->high + 1 - r->low;
|
||||
}
|
||||
sorted = tr_new( int, n );
|
||||
for( l=ranges; l!=NULL; l=l->next ) {
|
||||
const struct number_range * r = l->data;
|
||||
int i;
|
||||
for( i=r->low; i<=r->high; ++i )
|
||||
sorted[n2++] = i;
|
||||
}
|
||||
qsort( sorted, n, sizeof( int ), compareInt );
|
||||
assert( n == n2 );
|
||||
|
||||
/* remove duplicates */
|
||||
uniq = tr_new( int, n );
|
||||
for( i=n=0; i<n2; ++i )
|
||||
if( !n || uniq[n-1] != sorted[i] )
|
||||
uniq[n++] = sorted[i];
|
||||
|
||||
tr_free( sorted );
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
tr_list_free( &ranges, tr_free );
|
||||
tr_free( str );
|
||||
|
||||
/* return the result */
|
||||
*setmeCount = n;
|
||||
return uniq;
|
||||
}
|
||||
|
|
|
@ -451,6 +451,8 @@ static TR_INLINE tr_bool tr_bitfieldHas( const tr_bitfield * b, size_t nth )
|
|||
|
||||
double tr_getRatio( double numerator, double denominator );
|
||||
|
||||
int* tr_parseNumberRange( const char * str, int str_len, int * setmeCount );
|
||||
|
||||
|
||||
int tr_ptr2int( void* );
|
||||
|
||||
|
|
Loading…
Reference in a new issue