mirror of
https://github.com/curl/curl.git
synced 2026-08-26 11:33:34 +03:00
tool: support fractions for --limit-rate and --max-filesize
Allow 2.5k or 3.7M etc. Add mention in documentation. Verify in test case 1623. Closes #20266
This commit is contained in:
parent
6aaac9dd38
commit
6d6899c2f0
8 changed files with 250 additions and 48 deletions
|
|
@ -534,54 +534,93 @@ static ParameterError GetFileAndPassword(const char *nextarg, char **file,
|
|||
return err;
|
||||
}
|
||||
|
||||
struct sizeunit {
|
||||
char unit; /* single lowercase ASCII letter */
|
||||
curl_off_t mul;
|
||||
size_t mlen; /* number of digits in 'mul', when written in decimal */
|
||||
};
|
||||
|
||||
static const struct sizeunit *getunit(char unit)
|
||||
{
|
||||
static const struct sizeunit list[] = {
|
||||
{'p', (curl_off_t)1125899906842624, 16 }, /* Peta */
|
||||
{'t', (curl_off_t)1099511627776, 13 }, /* Tera */
|
||||
{'g', 1073741824, 10 }, /* Giga */
|
||||
{'m', 1048576, 7 }, /* Mega */
|
||||
{'k', 1024, 4 }, /* Kilo */
|
||||
};
|
||||
|
||||
size_t i;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(list); i++)
|
||||
if((unit | 0x20) == list[i].unit)
|
||||
return &list[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get a size parameter for '--limit-rate' or '--max-filesize'.
|
||||
* We support a 'G', 'M' or 'K' suffix too.
|
||||
We support P, T, G, M and K (case insensitive) suffixes.
|
||||
|
||||
Unit test 1623
|
||||
*/
|
||||
static ParameterError GetSizeParameter(const char *arg,
|
||||
const char *which,
|
||||
curl_off_t *value_out)
|
||||
UNITTEST ParameterError GetSizeParameter(const char *arg, curl_off_t *out)
|
||||
{
|
||||
const char *unit = arg;
|
||||
curl_off_t value;
|
||||
curl_off_t prec = 0;
|
||||
size_t plen = 0;
|
||||
curl_off_t add = 0;
|
||||
curl_off_t mul = 1;
|
||||
int rc;
|
||||
|
||||
if(curlx_str_number(&unit, &value, CURL_OFF_T_MAX)) {
|
||||
warnf("invalid number specified for %s", which);
|
||||
return PARAM_BAD_USE;
|
||||
rc = curlx_str_number(&unit, &value, CURL_OFF_T_MAX);
|
||||
if(rc == STRE_OVERFLOW)
|
||||
return PARAM_NUMBER_TOO_LARGE;
|
||||
else if(rc)
|
||||
return PARAM_BAD_NUMERIC;
|
||||
|
||||
if(!curlx_str_single(&unit, '.')) {
|
||||
const char *s = unit;
|
||||
if(curlx_str_number(&unit, &prec, CURL_OFF_T_MAX))
|
||||
return PARAM_BAD_NUMERIC;
|
||||
plen = unit - s;
|
||||
}
|
||||
|
||||
if(!*unit)
|
||||
unit = "b";
|
||||
else if(strlen(unit) > 1)
|
||||
unit = "w"; /* unsupported */
|
||||
|
||||
switch(*unit) {
|
||||
case 'G':
|
||||
case 'g':
|
||||
if(value > (CURL_OFF_T_MAX / (1024 * 1024 * 1024)))
|
||||
return PARAM_NUMBER_TOO_LARGE;
|
||||
value *= 1024 * 1024 * 1024;
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
if(value > (CURL_OFF_T_MAX / (1024 * 1024)))
|
||||
return PARAM_NUMBER_TOO_LARGE;
|
||||
value *= 1024 * 1024;
|
||||
break;
|
||||
case 'K':
|
||||
case 'k':
|
||||
if(value > (CURL_OFF_T_MAX / 1024))
|
||||
return PARAM_NUMBER_TOO_LARGE;
|
||||
value *= 1024;
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
/* for plain bytes, leave as-is */
|
||||
break;
|
||||
default:
|
||||
warnf("unsupported %s unit. Use G, M, K or B", which);
|
||||
if(strlen(unit) > 1)
|
||||
return PARAM_BAD_USE;
|
||||
else if(!*unit || ((*unit | 0x20) == 'b')) {
|
||||
if(plen)
|
||||
/* cannot handle partial bytes */
|
||||
return PARAM_BAD_USE;
|
||||
}
|
||||
*value_out = value;
|
||||
else {
|
||||
const struct sizeunit *su = getunit(*unit);
|
||||
if(!su)
|
||||
return PARAM_BAD_USE;
|
||||
mul = su->mul;
|
||||
|
||||
if(prec) {
|
||||
/* precision was provided */
|
||||
curl_off_t frac = 1;
|
||||
|
||||
/* too many precision digits, trim them */
|
||||
while(su->mlen <= plen) {
|
||||
prec /= 10;
|
||||
plen--;
|
||||
}
|
||||
|
||||
while(plen--)
|
||||
frac *= 10;
|
||||
|
||||
if((CURL_OFF_T_MAX / mul) > prec)
|
||||
add = mul * prec / frac;
|
||||
else
|
||||
add = (mul / frac) * prec;
|
||||
}
|
||||
}
|
||||
if(value > ((CURL_OFF_T_MAX - add) / mul))
|
||||
return PARAM_NUMBER_TOO_LARGE;
|
||||
|
||||
*out = value * mul + add;
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
|
|
@ -2365,7 +2404,7 @@ static ParameterError opt_string(struct OperationConfig *config,
|
|||
err = getstr(&config->dns_servers, nextarg, DENY_BLANK);
|
||||
break;
|
||||
case C_LIMIT_RATE: /* --limit-rate */
|
||||
err = GetSizeParameter(nextarg, "rate", &value);
|
||||
err = GetSizeParameter(nextarg, &value);
|
||||
if(!err) {
|
||||
config->recvpersecond = value;
|
||||
config->sendpersecond = value;
|
||||
|
|
@ -2401,7 +2440,7 @@ static ParameterError opt_string(struct OperationConfig *config,
|
|||
err = getstr(&config->haproxy_clientip, nextarg, DENY_BLANK);
|
||||
break;
|
||||
case C_MAX_FILESIZE: /* --max-filesize */
|
||||
err = GetSizeParameter(nextarg, "max-filesize", &value);
|
||||
err = GetSizeParameter(nextarg, &value);
|
||||
if(!err)
|
||||
config->max_filesize = value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -375,6 +375,7 @@ ParameterError getparameter(const char *flag, const char *nextarg,
|
|||
ParameterError parse_cert_parameter(const char *cert_parameter,
|
||||
char **certname,
|
||||
char **passphrase);
|
||||
UNITTEST ParameterError GetSizeParameter(const char *arg, curl_off_t *out);
|
||||
#endif
|
||||
|
||||
ParameterError parse_args(int argc, argv_item_t argv[]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue