- Better error handling (no errno mess), better limit checks.
- Also removed all uses of curlx_strtoofft()
Closes #16634
void Curl_str_trimblanks(struct Curl_str *out);
void Curl_str_passblanks(const char **linep);
+#define curlx_str_number(x,y,z) Curl_str_number(x,y,z)
+#define curlx_str_octal(x,y,z) Curl_str_octal(x,y,z)
+#define curlx_str_single(x,y) Curl_str_single(x,y)
+#define curlx_str_passblanks(x) Curl_str_passblanks(x)
+
#endif /* HEADER_CURL_STRPARSE_H */
***************************************************************************/
#include "curl_setup.h"
+#include "strparse.h"
typedef enum {
CURL_OFFT_OK, /* parsed fine */
enable STDERR
banfunc strncpy
banfunc sscanf
+banfunc strtol
+banfunc strtoul
#endif
#include "terminal.h"
+#include "strtoofft.h"
#include "memdebug.h" /* keep this as LAST include */
unsigned int width = 0;
char *colp = curl_getenv("COLUMNS");
if(colp) {
- char *endptr;
- long num = strtol(colp, &endptr, 10);
- if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) &&
- (num < 10000))
+ curl_off_t num;
+ const char *p = colp;
+ if(!curlx_str_number(&p, &num, 10000) && (num > 20))
width = (unsigned int)num;
curl_free(colp);
}
const char *loc = location;
size_t llen = loclen;
int space_skipped = 0;
- char *vver = getenv("VTE_VERSION");
+ const char *vver = getenv("VTE_VERSION");
if(vver) {
- long vvn = strtol(vver, NULL, 10);
- /* Skip formatting for old versions of VTE <= 0.48.1 (Mar 2017) since some
- of those versions have formatting bugs. (#10428) */
- if(0 < vvn && vvn <= 4801)
+ curl_off_t num;
+ if(curlx_str_number(&vver, &num, CURL_OFF_T_MAX) ||
+ /* Skip formatting for old versions of VTE <= 0.48.1 (Mar 2017) since
+ some of those versions have formatting bugs. (#10428) */
+ (num <= 4801))
goto locout;
}
const char *which,
curl_off_t *value_out)
{
- char *unit;
+ const char *unit = arg;
curl_off_t value;
- if(curlx_strtoofft(arg, &unit, 10, &value)) {
+ if(curlx_str_number(&unit, &value, CURL_OFF_T_MAX)) {
warnf(global, "invalid number specified for %s", which);
return PARAM_BAD_USE;
}
if(!*unit)
- unit = (char *)"b";
+ unit = "b";
else if(strlen(unit) > 1)
- unit = (char *)"w"; /* unsupported */
+ unit = "w"; /* unsupported */
switch(*unit) {
case 'G':
/d == per day (24 hours)
*/
ParameterError err = PARAM_OK;
- char *div = strchr(nextarg, '/');
+ const char *div = strchr(nextarg, '/');
char number[26];
long denominator;
long numerator = 60*60*1000; /* default per hour */
return PARAM_BAD_USE;
if(div) {
- char unit = div[1];
curl_off_t numunits;
- char *endp;
+ const char *s;
+ div++;
+ s = div;
- if(curlx_strtoofft(&div[1], &endp, 10, &numunits)) {
- /* if it fails, there is no legit number specified */
- if(endp == &div[1])
- /* if endp did not move, accept it as a 1 */
+ if(curlx_str_number(&div, &numunits, CURL_OFF_T_MAX)) {
+ if(s == div)
+ /* if div did not move, accept it as a 1 */
numunits = 1;
else
return PARAM_BAD_USE;
}
- else
- unit = *endp;
- switch(unit) {
+ switch(*div) {
case 's': /* per second */
numerator = 1000;
break;
const char *nextarg)
{
ParameterError err = PARAM_OK;
+ curl_off_t value;
+ const char *orig = nextarg;
if(config->use_resume) {
errorf(global, "--continue-at is mutually exclusive with --range");
return PARAM_BAD_USE;
}
- /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
- (and will not actually be range by definition). The manpage
- previously claimed that to be a good way, why this code is added to
- work-around it. */
- if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
+ if(!curlx_str_number(&nextarg, &value, CURL_OFF_T_MAX) &&
+ curlx_str_single(&nextarg, '-')) {
+ /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
+ (and will not actually be range by definition). The manpage previously
+ claimed that to be a good way, why this code is added to work-around
+ it. */
char buffer[32];
- curl_off_t value;
- if(curlx_strtoofft(nextarg, NULL, 10, &value)) {
- warnf(global, "unsupported range point");
- err = PARAM_BAD_USE;
- }
- else {
- warnf(global,
- "A specified range MUST include at least one dash (-). "
- "Appending one for you");
- msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-",
- value);
- Curl_safefree(config->range);
- config->range = strdup(buffer);
- if(!config->range)
- err = PARAM_NO_MEM;
- }
+ warnf(global, "A specified range MUST include at least one dash (-). "
+ "Appending one for you");
+ msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-",
+ value);
+ free(config->range);
+ config->range = strdup(buffer);
+ if(!config->range)
+ err = PARAM_NO_MEM;
}
else {
/* byte range requested */
- const char *tmp_range = nextarg;
- while(*tmp_range) {
- if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') {
+ while(*nextarg) {
+ if(!ISDIGIT(*nextarg) && *nextarg != '-' && *nextarg != ',') {
warnf(global, "Invalid character is found in given range. "
"A specified range MUST have only digits in "
"\'start\'-\'stop\'. The server's response to this "
"request is uncertain.");
break;
}
- tmp_range++;
+ nextarg++;
}
- err = getstr(&config->range, nextarg, DENY_BLANK);
+ err = getstr(&config->range, orig, DENY_BLANK);
}
return err;
}
/* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */
env = curl_getenv("CURL_MEMLIMIT");
if(env) {
- char *endptr;
- long num = strtol(env, &endptr, 10);
- if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
- curl_dbg_memlimit(num);
+ curl_off_t num;
+ const char *p = env;
+ if(!curlx_str_number(&p, &num, LONG_MAX))
+ curl_dbg_memlimit((long)num);
curl_free(env);
}
}
#ifdef DEBUGBUILD
char *env = getenv("CURL_BUFFERSIZE");
if(env) {
- long size = strtol(env, NULL, 10);
- if(size)
- my_setopt(curl, CURLOPT_BUFFERSIZE, size);
+ curl_off_t num;
+ const char *p = env;
+ if(!Curl_str_number(&p, &num, LONG_MAX))
+ my_setopt(curl, CURLOPT_BUFFERSIZE, (long)num);
}
else
#endif
#include "tool_setup.h"
#include "strcase.h"
-
#include "curlx.h"
#include "tool_cfgable.h"
*/
static ParameterError getnum(long *val, const char *str, int base)
{
+ DEBUGASSERT((base == 8) || (base == 10));
if(str) {
- char *endptr = NULL;
- long num;
- if(!str[0])
- return PARAM_BLANK_STRING;
- CURL_SETERRNO(0);
- num = strtol(str, &endptr, base);
- if(errno == ERANGE)
- return PARAM_NUMBER_TOO_LARGE;
- if((endptr != str) && (*endptr == '\0')) {
- *val = num;
+ curl_off_t num;
+ bool is_neg = FALSE;
+ if(base == 10) {
+ is_neg = (*str == '-');
+ if(is_neg)
+ str++;
+ if(curlx_str_number(&str, &num, LONG_MAX))
+ return PARAM_BAD_NUMERIC;
+ }
+ else { /* base == 8 */
+ if(curlx_str_octal(&str, &num, LONG_MAX))
+ return PARAM_BAD_NUMERIC;
+ }
+ if(!curlx_str_single(&str, '\0')) {
+ *val = (long)num;
+ if(is_neg)
+ *val = -*val;
return PARAM_OK; /* Ok */
}
}
return PARAM_OK;
}
-
-/*
- * Parse the string and write the double in the given address. Return PARAM_OK
- * on success, otherwise a parameter specific error enum.
- *
- * The 'max' argument is the maximum value allowed, as the numbers are often
- * multiplied when later used.
- *
- * Since this function gets called with the 'nextarg' pointer from within the
- * getparameter a lot, we must check it for NULL before accessing the str
- * data.
- */
-
-static ParameterError str2double(double *val, const char *str, double max)
-{
- if(str) {
- char *endptr;
- double num;
- CURL_SETERRNO(0);
- num = strtod(str, &endptr);
- if(errno == ERANGE)
- return PARAM_NUMBER_TOO_LARGE;
- if(num > max) {
- /* too large */
- return PARAM_NUMBER_TOO_LARGE;
- }
- if((endptr != str) && (endptr == str + strlen(str))) {
- *val = num;
- return PARAM_OK; /* Ok */
- }
- }
- return PARAM_BAD_NUMERIC; /* badness */
-}
-
/*
* Parse the string as seconds with decimals, and write the number of
* milliseconds that corresponds in the given address. Return PARAM_OK on
ParameterError secs2ms(long *valp, const char *str)
{
- double value;
- ParameterError result = str2double(&value, str, (double)LONG_MAX/1000);
- if(result != PARAM_OK)
- return result;
- if(value < 0)
- return PARAM_NEGATIVE_NUMERIC;
+ curl_off_t secs;
+ long ms = 0;
+ const unsigned int digs[] = { 1, 10, 100, 1000, 10000, 1000000,
+ 1000000, 10000000, 100000000 };
+ if(!str ||
+ curlx_str_number(&str, &secs, CURL_OFF_T_MAX/100))
+ return PARAM_BAD_NUMERIC;
+ if(!curlx_str_single(&str, '.')) {
+ curl_off_t fracs;
+ const char *s = str;
+ size_t len;
+ if(curlx_str_number(&str, &fracs, CURL_OFF_T_MAX))
+ return PARAM_NUMBER_TOO_LARGE;
+ /* how many milliseconds are in fracs ? */
+ len = (str - s);
+ while((len > sizeof(CURL_ARRAYSIZE(digs)) || (fracs > LONG_MAX/100))) {
+ fracs /= 10;
+ len--;
+ }
+ ms = ((long)fracs * 100) / digs[len - 1];
+ }
- *valp = (long)(value*1000);
+ *valp = (long)secs * 1000 + ms;
return PARAM_OK;
}
*/
ParameterError str2offset(curl_off_t *val, const char *str)
{
- char *endptr;
- if(str[0] == '-')
- /* offsets are not negative, this indicates weird input */
- return PARAM_NEGATIVE_NUMERIC;
-
-#if(SIZEOF_CURL_OFF_T > SIZEOF_LONG)
- {
- CURLofft offt = curlx_strtoofft(str, &endptr, 10, val);
- if(CURL_OFFT_FLOW == offt)
- return PARAM_NUMBER_TOO_LARGE;
- else if(CURL_OFFT_INVAL == offt)
- return PARAM_BAD_NUMERIC;
- }
-#else
- CURL_SETERRNO(0);
- *val = strtol(str, &endptr, 0);
- if((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)
- return PARAM_NUMBER_TOO_LARGE;
-#endif
- if((endptr != str) && (endptr == str + strlen(str)))
- return PARAM_OK;
-
- return PARAM_BAD_NUMERIC;
+ if(curlx_str_number(&str, val, CURL_OFF_T_MAX) ||
+ curlx_str_single(&str, '\0'))
+ return PARAM_BAD_NUMERIC;
+ return PARAM_OK;
}
#define MAX_USERPWDLENGTH (100*1024)
return 0;
}
-static CURLcode glob_set(struct URLGlob *glob, char **patternp,
+static CURLcode glob_set(struct URLGlob *glob, const char **patternp,
size_t *posp, curl_off_t *amount,
int globindex)
{
struct URLPattern *pat;
bool done = FALSE;
char *buf = glob->glob_buffer;
- char *pattern = *patternp;
- char *opattern = pattern;
+ const char *pattern = *patternp;
+ const char *opattern = pattern;
size_t opos = *posp-1;
pat = &glob->pattern[glob->size];
return CURLE_OK;
}
-static CURLcode glob_range(struct URLGlob *glob, char **patternp,
+static CURLcode glob_range(struct URLGlob *glob, const char **patternp,
size_t *posp, curl_off_t *amount,
int globindex)
{
expression is checked for well-formedness and collected until the next ']'
*/
struct URLPattern *pat;
- char *pattern = *patternp;
- char *c;
+ const char *pattern = *patternp;
+ const char *c;
pat = &glob->pattern[glob->size];
pat->globindex = globindex;
pmatch = TRUE;
if(end_c == ':') {
- char *endp;
- CURL_SETERRNO(0);
- step = strtoul(&pattern[4], &endp, 10);
- if(errno || &pattern[4] == endp || *endp != ']')
+ curl_off_t num;
+ const char *p = &pattern[4];
+ if(curlx_str_number(&p, &num, 256) || curlx_str_single(&p, ']'))
step = 0;
else
- pattern = endp + 1;
+ step = (unsigned long)num;
+ pattern = p;
}
else if(end_c != ']')
/* then this is wrong */
*posp += (pattern - *patternp);
- if(!pmatch || !step || step > (unsigned)INT_MAX ||
+ if(!pmatch || !step ||
(min_c == max_c && step != 1) ||
(min_c != max_c && (min_c > max_c || step > (unsigned)(max_c - min_c) ||
(max_c - min_c) > ('z' - 'a'))))
}
else if(ISDIGIT(*pattern)) {
/* numeric range detected */
- unsigned long min_n;
+ unsigned long min_n = 0;
unsigned long max_n = 0;
unsigned long step_n = 0;
- char *endp;
+ curl_off_t num;
pat->type = UPTNumRange;
pat->content.NumRange.padlength = 0;
}
}
- CURL_SETERRNO(0);
- min_n = strtoul(pattern, &endp, 10);
- if(errno || (endp == pattern))
- endp = NULL;
- else {
- if(*endp != '-')
- endp = NULL;
- else {
- pattern = endp + 1;
- while(ISBLANK(*pattern))
- pattern++;
- if(!ISDIGIT(*pattern)) {
- endp = NULL;
- goto fail;
- }
- CURL_SETERRNO(0);
- max_n = strtoul(pattern, &endp, 10);
- if(errno)
- /* overflow */
- endp = NULL;
- else if(*endp == ':') {
- pattern = endp + 1;
- CURL_SETERRNO(0);
- step_n = strtoul(pattern, &endp, 10);
- if(errno)
- /* over/underflow situation */
- endp = NULL;
- }
- else
- step_n = 1;
- if(endp && (*endp == ']')) {
- pattern = endp + 1;
+ if(!curlx_str_number(&pattern, &num, CURL_OFF_T_MAX)) {
+ min_n = (unsigned long)num;
+ if(!curlx_str_single(&pattern, '-')) {
+ curlx_str_passblanks(&pattern);
+ if(!curlx_str_number(&pattern, &num, CURL_OFF_T_MAX)) {
+ max_n = (unsigned long)num;
+ if(!curlx_str_single(&pattern, ']'))
+ step_n = 1;
+ else if(!curlx_str_single(&pattern, ':') &&
+ !curlx_str_number(&pattern, &num, CURL_OFF_T_MAX) &&
+ !curlx_str_single(&pattern, ']')) {
+ step_n = (unsigned long)num;
+ }
+ /* else bad syntax */
}
- else
- endp = NULL;
}
}
-fail:
*posp += (pattern - *patternp);
- if(!endp || !step_n ||
+ if(!step_n ||
(min_n == max_n && step_n != 1) ||
(min_n != max_n && (min_n > max_n || step_n > (max_n - min_n))))
/* the pattern is not well-formed */
return rc ? FALSE : TRUE;
}
-static CURLcode glob_parse(struct URLGlob *glob, char *pattern,
+static CURLcode glob_parse(struct URLGlob *glob, const char *pattern,
size_t pos, curl_off_t *amount)
{
/* processes a literal string component of a URL
#define MAX_OUTPUT_GLOB_LENGTH (10*1024)
-CURLcode glob_match_url(char **result, char *filename, struct URLGlob *glob)
+CURLcode glob_match_url(char **result, const char *filename,
+ struct URLGlob *glob)
{
char numbuf[18];
- char *appendthis = (char *)"";
+ const char *appendthis = (char *)"";
size_t appendlen = 0;
struct curlx_dynbuf dyn;
while(*filename) {
if(*filename == '#' && ISDIGIT(filename[1])) {
- char *ptr = filename;
- unsigned long num = strtoul(&filename[1], &filename, 10);
+ const char *ptr = filename;
+ curl_off_t num;
struct URLPattern *pat = NULL;
-
- if(num && (num < glob->size)) {
+ filename++;
+ if(!curlx_str_number(&filename, &num, glob->size) && num) {
unsigned long i;
num--; /* make it zero based */
/* find the correct glob entry */
CURLcode glob_url(struct URLGlob**, char *, curl_off_t *, FILE *);
CURLcode glob_next_url(char **, struct URLGlob *);
-CURLcode glob_match_url(char **, char *, struct URLGlob *);
+CURLcode glob_match_url(char **, const char *, struct URLGlob *);
void glob_cleanup(struct URLGlob **glob);
#endif /* HEADER_CURL_TOOL_URLGLOB_H */
clen = strlen(ge);
}
}
- if(*line == '[') {
+ if(*line == '[' && ISDIGIT(line[1])) {
/* is there a byte range specified? [num-num] */
- if(ISDIGIT(line[1])) {
- char *endp;
- if(curlx_strtoofft(&line[1], &endp, 10, &startoffset) || (*endp != '-'))
- return PARAM_VAR_SYNTAX;
- else {
- char *p = endp + 1; /* pass the '-' */
- if(*p != ']') {
- if(curlx_strtoofft(p, &endp, 10, &endoffset) || (*endp != ']'))
- return PARAM_VAR_SYNTAX;
- line = &endp[1]; /* pass the ']' */
- }
- else
- line = &p[1]; /* pass the ']' */
- }
- if(startoffset > endoffset)
+ line++;
+ if(curlx_str_number(&line, &startoffset, CURL_OFF_T_MAX) ||
+ curlx_str_single(&line, '-'))
+ return PARAM_VAR_SYNTAX;
+ if(curlx_str_single(&line, ']')) {
+ if(curlx_str_number(&line, &endoffset, CURL_OFF_T_MAX) ||
+ curlx_str_single(&line, ']'))
return PARAM_VAR_SYNTAX;
}
+ if(startoffset > endoffset)
+ return PARAM_VAR_SYNTAX;
}
if(content)
;