diff --git a/libtransmission/rpcimpl.c b/libtransmission/rpcimpl.c index 780ee706f..af9a0a4a0 100644 --- a/libtransmission/rpcimpl.c +++ b/libtransmission/rpcimpl.c @@ -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; ilow = 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