From b4538ec5229d716baa5e09b0f41b77c08c849c04 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 14 Feb 2025 11:29:08 +0100 Subject: [PATCH] strparse: switch to curl_off_t as base data type - add hex and octal parsers to the Curl_str_* family - make curlx_strtoofft use these parsers - remove all use of strtol() and strtoul() in library code - generally use Curl_str_* more than strtoofft, for stricter parsing - supports 64-bit universally, instead of 'long' which differs in size between platforms Extended the unit test 1664 to verify hex and octal parsing. Closes #16336 --- lib/.checksrc | 2 + lib/Makefile.inc | 1 + lib/altsvc.c | 23 +++-- lib/cf-socket.c | 20 ++-- lib/cfilters.c | 9 +- lib/conncache.c | 7 +- lib/cookie.c | 31 +++--- lib/curl_ctype.h | 1 + lib/curl_range.c | 33 +++--- lib/ftp.c | 27 +++-- lib/ftplistparser.c | 2 +- lib/getinfo.c | 22 ++-- lib/hostip.c | 13 +-- lib/hsts.c | 19 ++-- lib/http.c | 10 +- lib/imap.c | 8 +- lib/ldap.c | 4 +- lib/openldap.c | 4 +- lib/parsedate.c | 2 +- lib/request.c | 9 +- lib/rtsp.c | 4 +- lib/smtp.c | 2 +- lib/strcase.c | 59 ----------- lib/strequal.c | 88 ++++++++++++++++ lib/strparse.c | 55 ++++++++-- lib/strparse.h | 11 +- lib/strtoofft.c | 208 +++----------------------------------- lib/strtoofft.h | 16 --- lib/telnet.c | 4 +- lib/tftp.c | 13 +-- lib/url.c | 12 +-- lib/urlapi.c | 72 ++++++------- lib/vquic/.checksrc | 2 + lib/vquic/vquic.c | 6 +- lib/vssh/libssh.c | 22 ++-- lib/vssh/libssh2.c | 22 ++-- lib/vssh/wolfssh.c | 1 - lib/vtls/.checksrc | 2 + lib/vtls/schannel.c | 12 ++- lib/ws.c | 15 ++- projects/generate.bat | 4 + src/Makefile.inc | 4 + tests/data/test1664 | 38 ++++++- tests/server/Makefile.inc | 4 + tests/unit/unit1664.c | 104 +++++++++++++++++-- winbuild/MakefileBuild.vc | 6 ++ 46 files changed, 537 insertions(+), 496 deletions(-) create mode 100644 lib/strequal.c diff --git a/lib/.checksrc b/lib/.checksrc index 3985707fd9e4..3d4af2313b62 100644 --- a/lib/.checksrc +++ b/lib/.checksrc @@ -3,3 +3,5 @@ banfunc strncpy banfunc sscanf banfunc snprintf banfunc vsnprint +banfunc strtoul +banfunc strtol diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 25c6df84ecb9..0e6724bcdbe0 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -226,6 +226,7 @@ LIB_CFILES = \ splay.c \ strcase.c \ strdup.c \ + strequal.c \ strerror.c \ strparse.c \ strtok.c \ diff --git a/lib/altsvc.c b/lib/altsvc.c index a958ea58117b..c7449ab1068b 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -159,10 +159,10 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line) struct Curl_str srcalpn; struct Curl_str dstalpn; struct Curl_str date; - size_t srcport; - size_t dstport; - size_t persist; - size_t prio; + curl_off_t srcport; + curl_off_t dstport; + curl_off_t persist; + curl_off_t prio; if(Curl_str_word(&line, &srcalpn, MAX_ALTSVC_ALPNLEN) || Curl_str_singlespace(&line) || @@ -193,8 +193,8 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line) memcpy(dbuf, date.str, date.len); dbuf[date.len] = 0; expires = Curl_getdate_capped(dbuf); - as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn, srcport, - dstport); + as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn, + (size_t)srcport, (size_t)dstport); if(as) { as->expires = expires; as->prio = 0; /* not supported to just set zero */ @@ -465,10 +465,11 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid, return */ static time_t altsvc_debugtime(void *unused) { - char *timestr = getenv("CURL_TIME"); + const char *timestr = getenv("CURL_TIME"); (void)unused; if(timestr) { - long val = strtol(timestr, NULL, 10); + curl_off_t val; + Curl_str_number(×tr, &val, TIME_T_MAX); return (time_t)val; } return time(NULL); @@ -528,7 +529,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, size_t dstlen = 0; /* destination hostname length */ const char *value_ptr; char option[32]; - size_t num; + curl_off_t num; bool quoted = FALSE; time_t maxage = 24 * 3600; /* default is 24 hours */ bool persist = FALSE; @@ -566,7 +567,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, dstlen = strlen(srchost); } if(*p == ':') { - size_t port = 0; + curl_off_t port = 0; p++; if(Curl_str_number(&p, &port, 0xffff) || (*p != '\"')) { infof(data, "Unknown alt-svc port number, ignoring."); @@ -617,7 +618,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',') p++; } - if(!Curl_str_number(&value_ptr, &num, SIZE_T_MAX)) { + if(!Curl_str_number(&value_ptr, &num, TIME_T_MAX)) { if(strcasecompare("ma", option)) maxage = (time_t)num; else if(strcasecompare("persist", option) && (num == 1)) diff --git a/lib/cf-socket.c b/lib/cf-socket.c index b7262b19e9e3..abd485a97101 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -742,7 +742,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, Curl_printable_address. The latter returns only numeric scope IDs and the former returns none at all. So the scope ID, if present, is known to be numeric */ - size_t scope_id; + curl_off_t scope_id; if(Curl_str_number((const char **)&scope_ptr, &scope_id, UINT_MAX)) return CURLE_UNSUPPORTED_PROTOCOL; si6->sin6_scope_id = (unsigned int)scope_id; @@ -974,28 +974,28 @@ static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx, #ifdef DEBUGBUILD { - char *p = getenv("CURL_DBG_SOCK_WBLOCK"); + const char *p = getenv("CURL_DBG_SOCK_WBLOCK"); if(p) { - long l = strtol(p, NULL, 10); - if(l >= 0 && l <= 100) + curl_off_t l; + if(!Curl_str_number(&p, &l, 100)) ctx->wblock_percent = (int)l; } p = getenv("CURL_DBG_SOCK_WPARTIAL"); if(p) { - long l = strtol(p, NULL, 10); - if(l >= 0 && l <= 100) + curl_off_t l; + if(!Curl_str_number(&p, &l, 100)) ctx->wpartial_percent = (int)l; } p = getenv("CURL_DBG_SOCK_RBLOCK"); if(p) { - long l = strtol(p, NULL, 10); - if(l >= 0 && l <= 100) + curl_off_t l; + if(!Curl_str_number(&p, &l, 100)) ctx->rblock_percent = (int)l; } p = getenv("CURL_DBG_SOCK_RMAX"); if(p) { - long l = strtol(p, NULL, 10); - if(l >= 0) + curl_off_t l; + if(!Curl_str_number(&p, &l, SIZE_T_MAX)) ctx->recv_max = (size_t)l; } } diff --git a/lib/cfilters.c b/lib/cfilters.c index 6a894e8ce6e9..91f7325c3834 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -35,6 +35,7 @@ #include "progress.h" #include "select.h" #include "warnless.h" +#include "strparse.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -883,11 +884,11 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex, { /* Allow debug builds to override this logic to force short sends */ - char *p = getenv("CURL_SMALLSENDS"); + const char *p = getenv("CURL_SMALLSENDS"); if(p) { - size_t altsize = (size_t)strtoul(p, NULL, 10); - if(altsize) - write_len = CURLMIN(write_len, altsize); + curl_off_t altsize; + if(!Curl_str_number(&p, &altsize, SIZE_T_MAX)) + write_len = CURLMIN(write_len, (size_t)altsize); } } #endif diff --git a/lib/conncache.c b/lib/conncache.c index b8a0515276d1..2df29d9385fd 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -41,6 +41,7 @@ #include "connect.h" #include "select.h" #include "strcase.h" +#include "strparse.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -682,10 +683,10 @@ static void cpool_close_and_destroy_all(struct cpool *cpool) /* Just for testing, run graceful shutdown */ #ifdef DEBUGBUILD { - char *p = getenv("CURL_GRACEFUL_SHUTDOWN"); + const char *p = getenv("CURL_GRACEFUL_SHUTDOWN"); if(p) { - long l = strtol(p, NULL, 10); - if(l > 0 && l < INT_MAX) + curl_off_t l; + if(!Curl_str_number(&p, &l, INT_MAX)) timeout_ms = (int)l; } } diff --git a/lib/cookie.c b/lib/cookie.c index 6fdabfd7914f..f523bf5ed093 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -80,7 +80,6 @@ Example set of cookies: #include "sendf.h" #include "slist.h" #include "share.h" -#include "strtoofft.h" #include "strcase.h" #include "curl_get_line.h" #include "curl_memrchr.h" @@ -89,6 +88,7 @@ Example set of cookies: #include "fopen.h" #include "strdup.h" #include "llist.h" +#include "strparse.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -708,21 +708,22 @@ parse_cookie_header(struct Curl_easy *data, * client should discard the cookie. A value of zero means the * cookie should be discarded immediately. */ - CURLofft offt; + int rc; const char *maxage = valuep; - offt = curlx_strtoofft((*maxage == '\"') ? - &maxage[1] : &maxage[0], NULL, 10, - &co->expires); - switch(offt) { - case CURL_OFFT_FLOW: + if(*maxage == '\"') + maxage++; + rc = Curl_str_number(&maxage, &co->expires, CURL_OFF_T_MAX); + + switch(rc) { + case STRE_OVERFLOW: /* overflow, used max value */ co->expires = CURL_OFF_T_MAX; break; - case CURL_OFFT_INVAL: + default: /* negative or otherwise bad, expire */ co->expires = 1; break; - case CURL_OFFT_OK: + case STRE_OK: if(!co->expires) /* already expired */ co->expires = 1; @@ -915,16 +916,8 @@ parse_netscape(struct Cookie *co, } break; case 4: - { - char *endp; - const char *p; - /* make sure curlx_strtoofft won't read past the current field */ - for(p = ptr; p < &ptr[len] && ISDIGIT(*p); ++p) - ; - if(p == ptr || p != &ptr[len] || - curlx_strtoofft(ptr, &endp, 10, &co->expires) || endp != &ptr[len]) - return CERR_RANGE; - } + if(Curl_str_number(&ptr, &co->expires, CURL_OFF_T_MAX)) + return CERR_RANGE; break; case 5: co->name = Curl_memdup0(ptr, len); diff --git a/lib/curl_ctype.h b/lib/curl_ctype.h index b70acf3c5a66..48c3c37c359c 100644 --- a/lib/curl_ctype.h +++ b/lib/curl_ctype.h @@ -37,6 +37,7 @@ #define ISCNTRL(x) (ISLOWCNTRL(x) || IS7F(x)) #define ISALPHA(x) (ISLOWER(x) || ISUPPER(x)) #define ISXDIGIT(x) (ISDIGIT(x) || ISLOWHEXALHA(x) || ISUPHEXALHA(x)) +#define ISODIGIT(x) (((x) >= '0') && ((x) <= '7')) #define ISALNUM(x) (ISDIGIT(x) || ISLOWER(x) || ISUPPER(x)) #define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z')) #define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z')) diff --git a/lib/curl_range.c b/lib/curl_range.c index 49fb5f07783d..868c1e054be1 100644 --- a/lib/curl_range.c +++ b/lib/curl_range.c @@ -26,7 +26,7 @@ #include #include "curl_range.h" #include "sendf.h" -#include "strtoofft.h" +#include "strparse.h" /* Only include this function if one or more of FTP, FILE are enabled. */ #if !defined(CURL_DISABLE_FTP) || !defined(CURL_DISABLE_FILE) @@ -37,28 +37,29 @@ */ CURLcode Curl_range(struct Curl_easy *data) { - curl_off_t from, to; - char *ptr; - char *ptr2; - if(data->state.use_range && data->state.range) { - CURLofft from_t; - CURLofft to_t; - from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from); - if(from_t == CURL_OFFT_FLOW) - return CURLE_RANGE_ERROR; - while(*ptr && (ISBLANK(*ptr) || (*ptr == '-'))) - ptr++; - to_t = curlx_strtoofft(ptr, &ptr2, 10, &to); - if(to_t == CURL_OFFT_FLOW) + curl_off_t from, to; + bool first_num = TRUE; + const char *p = data->state.range; + if(Curl_str_number(&p, &from, CURL_OFF_T_MAX)) + first_num = FALSE; + + if(Curl_str_single(&p, '-')) + /* no leading dash or after the first number is an error */ return CURLE_RANGE_ERROR; - if((to_t == CURL_OFFT_INVAL) && !from_t) { + + if(Curl_str_number(&p, &to, CURL_OFF_T_MAX)) { + /* no second number */ /* X - */ data->state.resume_from = from; DEBUGF(infof(data, "RANGE %" FMT_OFF_T " to end of file", from)); } - else if((from_t == CURL_OFFT_INVAL) && !to_t) { + else if(!first_num) { /* -Y */ + if(!to) + /* "-0" is just wrong */ + return CURLE_RANGE_ERROR; + data->req.maxdownload = to; data->state.resume_from = -to; DEBUGF(infof(data, "RANGE the last %" FMT_OFF_T " bytes", to)); diff --git a/lib/ftp.c b/lib/ftp.c index 2210d8145f86..e38ee1b88d55 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -54,7 +54,6 @@ #include "ftplistparser.h" #include "curl_range.h" #include "curl_krb5.h" -#include "strtoofft.h" #include "strcase.h" #include "vtls/vtls.h" #include "cfilters.h" @@ -473,7 +472,7 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data) r += pp->nfinal; if(LASTLINE(r)) { - size_t status; + curl_off_t status; if(!Curl_str_number(&r, &status, 999) && (status == 226)) { /* funny timing situation where we get the final message on the control connection before traffic on the data connection has been @@ -544,7 +543,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data) static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn, const char *line, size_t len, int *code) { - size_t status; + curl_off_t status; (void)data; (void)conn; @@ -929,8 +928,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, if(ip_end) { const char *portp = strchr(ip_end, ':'); if(portp) { - size_t start; - size_t end; + curl_off_t start; + curl_off_t end; portp++; if(!Curl_str_number(&portp, &start, 0xffff)) { /* got the first number */ @@ -1767,7 +1766,7 @@ static bool match_pasv_6nums(const char *p, { int i; for(i = 0; i < 6; i++) { - size_t num; + curl_off_t num; if(i) { if(*p != ',') return FALSE; @@ -1805,11 +1804,9 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, ptr++; /* |||12345| */ sep = ptr[0]; - /* the ISDIGIT() check here is because strtoul() accepts leading minus - etc */ if((ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) { const char *p = &ptr[3]; - size_t num; + curl_off_t num; if(Curl_str_number(&p, &num, 0xffff) || (*p != sep)) { failf(data, "Illegal port number in EPSV reply"); return CURLE_FTP_WEIRD_PASV_REPLY; @@ -2297,7 +2294,7 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data, for all the digits at the end of the response and parse only those as a number. */ char *start = &buf[4]; - char *fdigit = memchr(start, '\r', len); + const char *fdigit = memchr(start, '\r', len); if(fdigit) { fdigit--; if(*fdigit == '\n') @@ -2307,9 +2304,8 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data, } else fdigit = start; - /* ignores parsing errors, which will make the size remain unknown */ - (void)curlx_strtoofft(fdigit, NULL, 10, &filesize); - + if(Curl_str_number(&fdigit, &filesize, CURL_OFF_T_MAX)) + filesize = -1; /* size remain unknown */ } else if(ftpcode == 550) { /* "No such file or directory" */ /* allow a SIZE failure for (resumed) uploads, when probing what command @@ -2471,7 +2467,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data, * those cases only confuses us. * * Example D above makes this parsing a little tricky */ - char *bytes; + const char *bytes; char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf); bytes = strstr(buf, " bytes"); if(bytes) { @@ -2493,7 +2489,8 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data, if(bytes) { ++bytes; /* get the number! */ - (void)curlx_strtoofft(bytes, NULL, 10, &size); + if(Curl_str_number(&bytes, &size, CURL_OFF_T_MAX)) + size = 1; } } } diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c index b4c0574785ae..8ca46998f565 100644 --- a/lib/ftplistparser.c +++ b/lib/ftplistparser.c @@ -547,7 +547,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, parser->item_length ++; if(c == ' ') { const char *p = &mem[parser->item_offset]; - size_t hlinks; + curl_off_t hlinks; mem[parser->item_offset + parser->item_length - 1] = 0; if(!Curl_str_number(&p, &hlinks, LONG_MAX)) { diff --git a/lib/getinfo.c b/lib/getinfo.c index ae6b3b8aa0f0..9b5912bac488 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -28,10 +28,10 @@ #include "urldata.h" #include "getinfo.h" - #include "vtls/vtls.h" #include "connect.h" /* Curl_getconnectinfo() */ #include "progress.h" +#include "strparse.h" /* The last #include files should be: */ #include "curl_memory.h" @@ -204,9 +204,10 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, } lptr; #ifdef DEBUGBUILD - char *timestr = getenv("CURL_TIME"); + const char *timestr = getenv("CURL_TIME"); if(timestr) { - unsigned long val = strtoul(timestr, NULL, 10); + curl_off_t val; + Curl_str_number(×tr, &val, TIME_T_MAX); switch(info) { case CURLINFO_LOCAL_PORT: *param_longp = (long)val; @@ -218,7 +219,8 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, /* use another variable for this to allow different values */ timestr = getenv("CURL_DEBUG_SIZE"); if(timestr) { - unsigned long val = strtoul(timestr, NULL, 10); + curl_off_t val; + Curl_str_number(×tr, &val, LONG_MAX); switch(info) { case CURLINFO_HEADER_SIZE: case CURLINFO_REQUEST_SIZE: @@ -379,9 +381,11 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, curl_off_t *param_offt) { #ifdef DEBUGBUILD - char *timestr = getenv("CURL_TIME"); + const char *timestr = getenv("CURL_TIME"); if(timestr) { - unsigned long val = strtoul(timestr, NULL, 10); + curl_off_t val; + Curl_str_number(×tr, &val, CURL_OFF_T_MAX); + switch(info) { case CURLINFO_TOTAL_TIME_T: case CURLINFO_NAMELOOKUP_TIME_T: @@ -476,9 +480,11 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, double *param_doublep) { #ifdef DEBUGBUILD - char *timestr = getenv("CURL_TIME"); + const char *timestr = getenv("CURL_TIME"); if(timestr) { - unsigned long val = strtoul(timestr, NULL, 10); + curl_off_t val; + Curl_str_number(×tr, &val, CURL_OFF_T_MAX); + switch(info) { case CURLINFO_TOTAL_TIME: case CURLINFO_NAMELOOKUP_TIME: diff --git a/lib/hostip.c b/lib/hostip.c index d14476ccaeb6..4dbedfb01206 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -1134,7 +1134,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) if(!hostp->data) continue; if(hostp->data[0] == '-') { - size_t num = 0; + curl_off_t num = 0; size_t entry_len; size_t hlen = 0; host_end = strchr(&hostp->data[1], ':'); @@ -1173,7 +1173,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) const char *addr_begin; const char *addr_end; const char *port_ptr; - size_t port = 0; + curl_off_t port = 0; const char *end_ptr; bool permanent = TRUE; bool error = TRUE; @@ -1273,8 +1273,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); if(dns) { - infof(data, "RESOLVE %.*s:%zd - old addresses discarded", - (int)hlen, host_begin, port); + infof(data, "RESOLVE %.*s:%" CURL_FORMAT_CURL_OFF_T + " - old addresses discarded", (int)hlen, host_begin, port); /* delete old entry, there are two reasons for this 1. old entry may have different addresses. 2. even if entry with correct addresses is already in the cache, @@ -1306,14 +1306,15 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) return CURLE_OUT_OF_MEMORY; } #ifndef CURL_DISABLE_VERBOSE_STRINGS - infof(data, "Added %.*s:%zd:%s to DNS cache%s", + infof(data, "Added %.*s:%" CURL_FORMAT_CURL_OFF_T ":%s to DNS cache%s", (int)hlen, host_begin, port, addresses, permanent ? "" : " (non-permanent)"); #endif /* Wildcard hostname */ if((hlen == 1) && (host_begin[0] == '*')) { - infof(data, "RESOLVE *:%zd using wildcard", port); + infof(data, "RESOLVE *:%" CURL_FORMAT_CURL_OFF_T " using wildcard", + port); data->state.wildcard_resolve = TRUE; } } diff --git a/lib/hsts.c b/lib/hsts.c index 1dcaf026ac92..1c729d94cbd5 100644 --- a/lib/hsts.c +++ b/lib/hsts.c @@ -35,7 +35,6 @@ #include "curl_get_line.h" #include "strcase.h" #include "sendf.h" -#include "strtoofft.h" #include "parsedate.h" #include "fopen.h" #include "rename.h" @@ -59,13 +58,12 @@ time_t deltatime; /* allow for "adjustments" for unit test purposes */ static time_t hsts_debugtime(void *unused) { - char *timestr = getenv("CURL_TIME"); + const char *timestr = getenv("CURL_TIME"); (void)unused; if(timestr) { curl_off_t val; - (void)curlx_strtoofft(timestr, NULL, 10, &val); - - val += (curl_off_t)deltatime; + if(!Curl_str_number(×tr, &val, TIME_T_MAX)) + val += (curl_off_t)deltatime; return (time_t)val; } return time(NULL); @@ -160,8 +158,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, p++; if(strncasecompare("max-age", p, 7)) { bool quoted = FALSE; - CURLofft offt; - char *endp; + int rc; if(gotma) return CURLE_BAD_FUNCTION_ARGUMENT; @@ -178,13 +175,13 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, p++; quoted = TRUE; } - offt = curlx_strtoofft(p, &endp, 10, &expires); - if(offt == CURL_OFFT_FLOW) + rc = Curl_str_number(&p, &expires, TIME_T_MAX); + if(rc == STRE_OVERFLOW) expires = CURL_OFF_T_MAX; - else if(offt) + else if(rc) /* invalid max-age */ return CURLE_BAD_FUNCTION_ARGUMENT; - p = endp; + if(quoted) { if(*p != '\"') return CURLE_BAD_FUNCTION_ARGUMENT; diff --git a/lib/http.c b/lib/http.c index 9e15afe46a1d..8010b4d92d05 100644 --- a/lib/http.c +++ b/lib/http.c @@ -86,6 +86,7 @@ #include "hsts.h" #include "ws.h" #include "curl_ctype.h" +#include "strparse.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -3072,11 +3073,10 @@ static CURLcode http_header(struct Curl_easy *data, /* if it truly stopped on a digit */ if(ISDIGIT(*ptr)) { - if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) { - if(data->state.resume_from == k->offset) - /* we asked for a resume and we got it */ - k->content_range = TRUE; - } + if(!Curl_str_number(&ptr, &k->offset, CURL_OFF_T_MAX) && + (data->state.resume_from == k->offset)) + /* we asked for a resume and we got it */ + k->content_range = TRUE; } else if(k->httpcode < 300) data->state.resume_from = 0; /* get everything */ diff --git a/lib/imap.c b/lib/imap.c index c15e96e7f85d..0672b32af50b 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -64,7 +64,7 @@ #include "socks.h" #include "imap.h" #include "mime.h" -#include "strtoofft.h" +#include "strparse.h" #include "strcase.h" #include "vtls/vtls.h" #include "cfilters.h" @@ -1156,9 +1156,9 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, the continuation data contained within the curly brackets */ ptr = memchr(ptr, '{', len); if(ptr) { - char *endptr; - if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) && - (endptr - ptr > 1 && *endptr == '}')) + ptr++; + if(!Curl_str_number(&ptr, &size, CURL_OFF_T_MAX) && + !Curl_str_single(&ptr, '}')) parsed = TRUE; } diff --git a/lib/ldap.c b/lib/ldap.c index 77bd9fba67af..dfabf55d118a 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -728,7 +728,9 @@ static void _ldap_trace(const char *fmt, ...) if(do_trace == -1) { const char *env = getenv("CURL_TRACE"); - do_trace = (env && strtol(env, NULL, 10) > 0); + curl_off_t e = 0; + if(!Curl_str_number(&env, &e, INT_MAX)) + do_trace = e > 0; } if(!do_trace) return; diff --git a/lib/openldap.c b/lib/openldap.c index 22e5bdd27901..13f8abf19130 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -560,7 +560,9 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done) #ifdef CURL_OPENLDAP_DEBUG if(do_trace < 0) { const char *env = getenv("CURL_OPENLDAP_TRACE"); - do_trace = (env && strtol(env, NULL, 10) > 0); + curl_off_t e = 0; + if(!Curl_str_number(&env, &e, INT_MAX)) + do_trace = e > 0; } if(do_trace) ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace); diff --git a/lib/parsedate.c b/lib/parsedate.c index 030a3c59b822..1795d6df6cdb 100644 --- a/lib/parsedate.c +++ b/lib/parsedate.c @@ -420,7 +420,7 @@ static int parsedate(const char *date, time_t *output) date = end; } else { - size_t lval; + curl_off_t lval; int num_digits = 0; const char *p = date; if(Curl_str_number(&p, &lval, 99999999)) diff --git a/lib/request.c b/lib/request.c index d5f04e9f1d6f..6e98879c3178 100644 --- a/lib/request.c +++ b/lib/request.c @@ -34,6 +34,7 @@ #include "sendf.h" #include "transfer.h" #include "url.h" +#include "strparse.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -194,11 +195,11 @@ static CURLcode xfer_send(struct Curl_easy *data, /* Allow debug builds to override this logic to force short initial sends */ size_t body_len = blen - hds_len; - char *p = getenv("CURL_SMALLREQSEND"); + const char *p = getenv("CURL_SMALLREQSEND"); if(p) { - size_t body_small = (size_t)strtoul(p, NULL, 10); - if(body_small && body_small < body_len) - blen = hds_len + body_small; + curl_off_t body_small; + if(!Curl_str_number(&p, &body_small, body_len)) + blen = hds_len + (size_t)body_small; } } #endif diff --git a/lib/rtsp.c b/lib/rtsp.c index 253c4551a073..652734ee2d2f 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -926,7 +926,7 @@ CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len) CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header) { if(checkprefix("CSeq:", header)) { - size_t CSeq = 0; + curl_off_t CSeq = 0; struct RTSP *rtsp = data->req.p.rtsp; const char *p = &header[5]; while(ISBLANK(*p)) @@ -1007,7 +1007,7 @@ CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport) start++; end = strchr(start, ';'); if(checkprefix("interleaved=", start)) { - size_t chan1, chan2, chan; + curl_off_t chan1, chan2, chan; const char *p = start + 12; if(!Curl_str_number(&p, &chan1, 255)) { unsigned char *rtp_channel_mask = data->state.rtp_channel_mask; diff --git a/lib/smtp.c b/lib/smtp.c index e5ad4f56b1a0..ffb23a6a8630 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -215,7 +215,7 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn, only send the response code instead as per Section 4.2. */ if(line[3] == ' ' || len == 5) { char tmpline[6]; - size_t code; + curl_off_t code; const char *p = tmpline; result = TRUE; memcpy(tmpline, line, (len == 5 ? 5 : 3)); diff --git a/lib/strcase.c b/lib/strcase.c index 7ae0929af3bf..841949ec5e9c 100644 --- a/lib/strcase.c +++ b/lib/strcase.c @@ -82,65 +82,6 @@ char Curl_raw_tolower(char in) return (char)tolowermap[(unsigned char) in]; } -/* - * curl_strequal() is for doing "raw" case insensitive strings. This is meant - * to be locale independent and only compare strings we know are safe for - * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for - * further explanations as to why this function is necessary. - */ - -static int casecompare(const char *first, const char *second) -{ - while(*first) { - if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) - /* get out of the loop as soon as they do not match */ - return 0; - first++; - second++; - } - /* If we are here either the strings are the same or the length is different. - We can just test if the "current" character is non-zero for one and zero - for the other. Note that the characters may not be exactly the same even - if they match, we only want to compare zero-ness. */ - return !*first == !*second; -} - -/* --- public function --- */ -int curl_strequal(const char *first, const char *second) -{ - if(first && second) - /* both pointers point to something then compare them */ - return casecompare(first, second); - - /* if both pointers are NULL then treat them as equal */ - return NULL == first && NULL == second; -} - -static int ncasecompare(const char *first, const char *second, size_t max) -{ - while(*first && max) { - if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) - return 0; - max--; - first++; - second++; - } - if(0 == max) - return 1; /* they are equal this far */ - - return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); -} - -/* --- public function --- */ -int curl_strnequal(const char *first, const char *second, size_t max) -{ - if(first && second) - /* both pointers point to something then compare them */ - return ncasecompare(first, second, max); - - /* if both pointers are NULL then treat them as equal if max is non-zero */ - return NULL == first && NULL == second && max; -} /* Copy an upper case version of the string from src to dest. The * strings may overlap. No more than n characters of the string are copied * (including any NUL) and the destination string will NOT be diff --git a/lib/strequal.c b/lib/strequal.c new file mode 100644 index 000000000000..d1ba91501bbe --- /dev/null +++ b/lib/strequal.c @@ -0,0 +1,88 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include +#include "strcase.h" + +/* + * curl_strequal() is for doing "raw" case insensitive strings. This is meant + * to be locale independent and only compare strings we know are safe for + * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for + * further explanations as to why this function is necessary. + */ + +static int casecompare(const char *first, const char *second) +{ + while(*first) { + if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) + /* get out of the loop as soon as they do not match */ + return 0; + first++; + second++; + } + /* If we are here either the strings are the same or the length is different. + We can just test if the "current" character is non-zero for one and zero + for the other. Note that the characters may not be exactly the same even + if they match, we only want to compare zero-ness. */ + return !*first == !*second; +} + +static int ncasecompare(const char *first, const char *second, size_t max) +{ + while(*first && max) { + if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) + return 0; + max--; + first++; + second++; + } + if(0 == max) + return 1; /* they are equal this far */ + + return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); +} + +/* --- public function --- */ +int curl_strequal(const char *first, const char *second) +{ + if(first && second) + /* both pointers point to something then compare them */ + return casecompare(first, second); + + /* if both pointers are NULL then treat them as equal */ + return NULL == first && NULL == second; +} + +/* --- public function --- */ +int curl_strnequal(const char *first, const char *second, size_t max) +{ + if(first && second) + /* both pointers point to something then compare them */ + return ncasecompare(first, second, max); + + /* if both pointers are NULL then treat them as equal if max is non-zero */ + return NULL == first && NULL == second && max; +} diff --git a/lib/strparse.c b/lib/strparse.c index c540148c9a30..6730b96d1b29 100644 --- a/lib/strparse.c +++ b/lib/strparse.c @@ -23,6 +23,7 @@ ***************************************************************************/ #include "strparse.h" +#include "strcase.h" /* Get a word until the first DELIM or end of string. At least one byte long. return non-zero on error */ @@ -103,28 +104,64 @@ int Curl_str_singlespace(const char **linep) return Curl_str_single(linep, ' '); } -/* Get an unsigned number. Leading zeroes are accepted. - return non-zero on error */ -int Curl_str_number(const char **linep, size_t *nump, size_t max) +/* given an ASCII hexadecimal character, return the value */ +#define HEXDIGIT2NUM(x) \ + (((x) > '9') ? Curl_raw_tolower(x) - 'a' + 10 : x - '0') + +/* given an ASCII character and a given base, return TRUE if valid */ +#define valid_digit(digit, base) \ + (((base == 10) && ISDIGIT(digit)) || \ + ((base == 16) && ISXDIGIT(digit)) || \ + ((base == 8) && ISODIGIT(digit))) + +/* given an ASCII character and a given base, return the value */ +#define num_digit(digit, base) \ + ((base != 16) ? digit - '0' : HEXDIGIT2NUM(digit)) + +/* no support for 0x prefix nor leading spaces */ +static int str_num_base(const char **linep, curl_off_t *nump, curl_off_t max, + int base) /* 8, 10 or 16, nothing else */ { - size_t num = 0; + curl_off_t num = 0; DEBUGASSERT(linep && *linep && nump); + DEBUGASSERT((base == 8) || (base == 10) || (base == 16)); *nump = 0; - if(!ISDIGIT(**linep)) + if(!valid_digit(**linep, base)) return STRE_NO_NUM; do { - int n = **linep - '0'; - if(num > ((SIZE_T_MAX - n) / 10)) + int n = num_digit(**linep, base); + if(num > ((CURL_OFF_T_MAX - n) / base)) return STRE_OVERFLOW; - num = num * 10 + n; + num = num * base + n; if(num > max) return STRE_BIG; /** too big */ (*linep)++; - } while(ISDIGIT(**linep)); + } while(valid_digit(**linep, base)); *nump = num; return STRE_OK; } +/* Get an unsigned decimal number with no leading space or minus. Leading + zeroes are accepted. return non-zero on error */ +int Curl_str_number(const char **linep, curl_off_t *nump, curl_off_t max) +{ + return str_num_base(linep, nump, max, 10); +} + +/* Get an unsigned hexadecimal number with no leading space or minus and no + "0x" support. Leading zeroes are accepted. return non-zero on error */ +int Curl_str_hex(const char **linep, curl_off_t *nump, curl_off_t max) +{ + return str_num_base(linep, nump, max, 16); +} + +/* Get an unsigned octal number with no leading space or minus and no "0" + prefix support. Leading zeroes are accepted. return non-zero on error */ +int Curl_str_octal(const char **linep, curl_off_t *nump, curl_off_t max) +{ + return str_num_base(linep, nump, max, 8); +} + /* CR or LF return non-zero on error */ int Curl_str_newline(const char **linep) diff --git a/lib/strparse.h b/lib/strparse.h index 77171f59a1f4..7ade183ec22b 100644 --- a/lib/strparse.h +++ b/lib/strparse.h @@ -62,9 +62,14 @@ int Curl_str_single(const char **linep, char byte); return non-zero on error */ int Curl_str_singlespace(const char **linep); -/* Get an unsigned number - return non-zero on error */ -int Curl_str_number(const char **linep, size_t *nump, size_t max); +/* Get an unsigned decimal number. Return non-zero on error */ +int Curl_str_number(const char **linep, curl_off_t *nump, curl_off_t max); + +/* Get an unsigned hexadecimal number. Return non-zero on error */ +int Curl_str_hex(const char **linep, curl_off_t *nump, curl_off_t max); + +/* Get an unsigned octal number. Return non-zero on error */ +int Curl_str_octal(const char **linep, curl_off_t *nump, curl_off_t max); /* Check for CR or LF return non-zero on error */ diff --git a/lib/strtoofft.c b/lib/strtoofft.c index 05536c182613..5a7f058f9662 100644 --- a/lib/strtoofft.c +++ b/lib/strtoofft.c @@ -22,216 +22,36 @@ * ***************************************************************************/ -#include #include "curl_setup.h" #include "strtoofft.h" +#include "strparse.h" /* - * NOTE: - * - * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we - * could use in case strtoll() does not exist... See - * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html - */ - -#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) -# ifdef HAVE_STRTOLL -# define strtooff strtoll -# else -# if defined(_MSC_VER) && (_MSC_VER >= 1300) -# if defined(_SAL_VERSION) - _Check_return_ _CRTIMP __int64 __cdecl _strtoi64( - _In_z_ const char *_String, - _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix); -# else - _CRTIMP __int64 __cdecl _strtoi64(const char *_String, - char **_EndPtr, int _Radix); -# endif -# define strtooff _strtoi64 -# else -# define PRIVATE_STRTOOFF 1 -# endif -# endif -#else -# define strtooff strtol -#endif - -#ifdef PRIVATE_STRTOOFF - -/* Range tests can be used for alphanum decoding if characters are consecutive, - like in ASCII. Else an array is scanned. Determine this condition now. */ - -#if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25 - -#define NO_RANGE_TEST - -static const char valchars[] = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -#endif - -static int get_char(char c, int base); - -/** - * Custom version of the strtooff function. This extracts a curl_off_t - * value from the given input string and returns it. - */ -static curl_off_t strtooff(const char *nptr, char **endptr, int base) -{ - char *end; - bool is_negative = FALSE; - bool overflow = FALSE; - int i; - curl_off_t value = 0; - - /* Skip leading whitespace. */ - end = (char *)nptr; - while(ISBLANK(end[0])) { - end++; - } - - /* Handle the sign, if any. */ - if(end[0] == '-') { - is_negative = TRUE; - end++; - } - else if(end[0] == '+') { - end++; - } - else if(end[0] == '\0') { - /* We had nothing but perhaps some whitespace -- there was no number. */ - if(endptr) { - *endptr = end; - } - return 0; - } - - /* Handle special beginnings, if present and allowed. */ - if(end[0] == '0' && end[1] == 'x') { - if(base == 16 || base == 0) { - end += 2; - base = 16; - } - } - else if(end[0] == '0') { - if(base == 8 || base == 0) { - end++; - base = 8; - } - } - - /* Matching strtol, if the base is 0 and it does not look like - * the number is octal or hex, we assume it is base 10. - */ - if(base == 0) { - base = 10; - } - - /* Loop handling digits. */ - for(i = get_char(end[0], base); - i != -1; - end++, i = get_char(end[0], base)) { - - if(value > (CURL_OFF_T_MAX - i) / base) { - overflow = TRUE; - break; - } - value = base * value + i; - } - - if(!overflow) { - if(is_negative) { - /* Fix the sign. */ - value *= -1; - } - } - else { - if(is_negative) - value = CURL_OFF_T_MIN; - else - value = CURL_OFF_T_MAX; - - errno = ERANGE; - } - - if(endptr) - *endptr = end; - - return value; -} - -/** - * Returns the value of c in the given base, or -1 if c cannot - * be interpreted properly in that base (i.e., is out of range, - * is a null, etc.). - * - * @param c the character to interpret according to base - * @param base the base in which to interpret c - * - * @return the value of c in base, or -1 if c is not in range - */ -static int get_char(char c, int base) -{ -#ifndef NO_RANGE_TEST - int value = -1; - if(c <= '9' && c >= '0') { - value = c - '0'; - } - else if(c <= 'Z' && c >= 'A') { - value = c - 'A' + 10; - } - else if(c <= 'z' && c >= 'a') { - value = c - 'a' + 10; - } -#else - const char *cp; - int value; - - cp = memchr(valchars, c, 10 + 26 + 26); - - if(!cp) - return -1; - - value = cp - valchars; - - if(value >= 10 + 26) - value -= 26; /* Lowercase. */ -#endif - - if(value >= base) { - value = -1; - } - - return value; -} -#endif /* Only present if we need strtoll, but do not have it. */ - -/* - * Parse a *positive* up to 64-bit number written in ASCII. + * Parse a positive number up to 63-bit number written in ASCII. Skip leading + * blanks. No support for prefixes. */ CURLofft curlx_strtoofft(const char *str, char **endp, int base, curl_off_t *num) { - char *end = NULL; curl_off_t number; - errno = 0; + int rc; *num = 0; /* clear by default */ - DEBUGASSERT(base); /* starting now, avoid base zero */ + DEBUGASSERT((base == 10) || (base == 16)); while(*str && ISBLANK(*str)) str++; - if(('-' == *str) || (ISSPACE(*str))) { - if(endp) - *endp = (char *)str; /* did not actually move */ - return CURL_OFFT_INVAL; /* nothing parsed */ - } - number = strtooff(str, &end, base); + + rc = base == 10 ? + Curl_str_number(&str, &number, CURL_OFF_T_MAX) : + Curl_str_hex(&str, &number, CURL_OFF_T_MAX); + if(endp) - *endp = end; - if(errno == ERANGE) - /* overflow/underflow */ + *endp = (char *)str; + if(rc == STRE_OVERFLOW) + /* overflow */ return CURL_OFFT_FLOW; - else if(str == end) + else if(rc) /* nothing parsed */ return CURL_OFFT_INVAL; diff --git a/lib/strtoofft.h b/lib/strtoofft.h index 71808b719c9b..051ab3064d8d 100644 --- a/lib/strtoofft.h +++ b/lib/strtoofft.h @@ -26,22 +26,6 @@ #include "curl_setup.h" -/* - * Determine which string to integral data type conversion function we use - * to implement string conversion to our curl_off_t integral data type. - * - * Notice that curl_off_t might be 64 or 32 bits wide, and that it might use - * an underlying data type which might be 'long', 'int64_t', 'long long' or - * '__int64' and more remotely other data types. - * - * On systems where the size of curl_off_t is greater than the size of 'long' - * the conversion function to use is strtoll() if it is available, otherwise, - * we emulate its functionality with our own clone. - * - * On systems where the size of curl_off_t is smaller or equal than the size - * of 'long' the conversion function to use is strtol(). - */ - typedef enum { CURL_OFFT_OK, /* parsed fine */ CURL_OFFT_FLOW, /* over or underflow */ diff --git a/lib/telnet.c b/lib/telnet.c index bd85b119ec59..97972482bd13 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -864,8 +864,8 @@ static CURLcode check_telnet_options(struct Curl_easy *data) /* Window Size */ if(strncasecompare(option, "WS", 2)) { const char *p = arg; - size_t x = 0; - size_t y = 0; + curl_off_t x = 0; + curl_off_t y = 0; if(Curl_str_number(&p, &x, 0xffff) || Curl_str_single(&p, 'x') || Curl_str_number(&p, &y, 0xffff)) { diff --git a/lib/tftp.c b/lib/tftp.c index 7f1eef518827..5fb8f3157e0b 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -331,7 +331,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state, infof(data, "got option=(%s) value=(%s)", option, value); if(checkprefix(TFTP_OPTION_BLKSIZE, option)) { - size_t blksize; + curl_off_t blksize; if(Curl_str_number(&value, &blksize, TFTP_BLKSIZE_MAX)) { failf(data, "%s (%d)", "blksize is larger than max supported", TFTP_BLKSIZE_MAX); @@ -350,8 +350,8 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state, /* could realloc pkt buffers here, but the spec does not call out * support for the server requesting a bigger blksize than the client * requests */ - failf(data, "server requested blksize larger than allocated (%zd)", - blksize); + failf(data, "server requested blksize larger than allocated (%" + CURL_FORMAT_CURL_OFF_T ")", blksize); return CURLE_TFTP_ILLEGAL; } @@ -360,16 +360,17 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state, state->blksize, state->requested_blksize); } else if(checkprefix(TFTP_OPTION_TSIZE, option)) { - size_t tsize = 0; + curl_off_t tsize = 0; /* tsize should be ignored on upload: Who cares about the size of the remote file? */ if(!data->state.upload && - !Curl_str_number(&value, &tsize, SIZE_T_MAX)) { + !Curl_str_number(&value, &tsize, CURL_OFF_T_MAX)) { if(!tsize) { failf(data, "invalid tsize -:%s:- value in OACK packet", value); return CURLE_TFTP_ILLEGAL; } - infof(data, "tsize parsed from OACK (%zd)", tsize); + infof(data, "tsize parsed from OACK (%" CURL_FORMAT_CURL_OFF_T ")", + tsize); Curl_pgrsSetDownloadSize(data, tsize); } } diff --git a/lib/url.c b/lib/url.c index 564971d68e93..cdca4b707228 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1681,7 +1681,7 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data, if(!uc && zoneid) { const char *p = zoneid; - size_t scope; + curl_off_t scope; if(!Curl_str_number(&p, &scope, UINT_MAX)) /* A plain number, use it directly as a scope id. */ conn->scope_id = (unsigned int)scope; @@ -1919,7 +1919,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } else { - size_t port; + curl_off_t port; bool valid = TRUE; if(data->set.use_port && data->state.allow_port) port = data->set.use_port; @@ -2258,7 +2258,7 @@ static CURLcode parse_proxy(struct Curl_easy *data, (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0); if(portptr) { - size_t num; + curl_off_t num; const char *p = portptr; if(!Curl_str_number(&p, &num, 0xffff)) port = (int)num; @@ -2902,7 +2902,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data, *host_portno = '\0'; /* cut off number from hostname */ host_portno++; if(*host_portno) { - size_t portparse; + curl_off_t portparse; const char *p = host_portno; if(Curl_str_number(&p, &portparse, 0xffff)) { failf(data, "No valid port number in connect to host string (%s)", @@ -2981,9 +2981,9 @@ static CURLcode parse_connect_to_string(struct Curl_easy *data, /* check whether the URL's port matches */ char *ptr_next = strchr(ptr, ':'); if(ptr_next) { - size_t port_to_match; + curl_off_t port_to_match; if(!Curl_str_number(&ptr, &port_to_match, 0xffff) && - (port_to_match == (size_t)conn->remote_port)) + (port_to_match == (curl_off_t)conn->remote_port)) port_match = TRUE; ptr = ptr_next + 1; } diff --git a/lib/urlapi.c b/lib/urlapi.c index 33684ccee175..a3aac4f2fff7 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -468,7 +468,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, portptr = strchr(hostname, ':'); if(portptr) { - size_t port; + curl_off_t port; size_t keep = portptr - hostname; /* Browser behavior adaptation. If there is a colon with no digits after, @@ -489,7 +489,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, u->portnum = (unsigned short) port; /* generate a new port number string to get rid of leading zeroes etc */ free(u->port); - u->port = aprintf("%zd", port); + u->port = aprintf("%" CURL_FORMAT_CURL_OFF_T, port); if(!u->port) return CURLUE_OUT_OF_MEMORY; } @@ -596,7 +596,7 @@ static int ipv4_normalize(struct dynbuf *host) bool done = FALSE; int n = 0; const char *c = Curl_dyn_ptr(host); - unsigned long parts[4] = {0, 0, 0, 0}; + unsigned int parts[4] = {0, 0, 0, 0}; CURLcode result = CURLE_OK; if(*c == '[') @@ -604,22 +604,24 @@ static int ipv4_normalize(struct dynbuf *host) errno = 0; /* for strtoul */ while(!done) { - char *endp = NULL; - unsigned long l; - if(!ISDIGIT(*c)) - /* most importantly this does not allow a leading plus or minus */ - return HOST_NAME; - l = strtoul(c, &endp, 0); - if(errno) - return HOST_NAME; -#if SIZEOF_LONG > 4 - /* a value larger than 32 bits */ - if(l > UINT_MAX) + int rc; + curl_off_t l; + if(*c == '0') { + c++; + if(*c == 'x') { + c++; /* skip the prefix */ + rc = Curl_str_hex(&c, &l, UINT_MAX); + } + else + rc = Curl_str_octal(&c, &l, UINT_MAX); + } + else + rc = Curl_str_number(&c, &l, UINT_MAX); + + if(rc) return HOST_NAME; -#endif - parts[n] = l; - c = endp; + parts[n] = (unsigned int)l; switch(*c) { case '.': @@ -643,30 +645,30 @@ static int ipv4_normalize(struct dynbuf *host) Curl_dyn_reset(host); result = Curl_dyn_addf(host, "%u.%u.%u.%u", - (unsigned int)(parts[0] >> 24), - (unsigned int)((parts[0] >> 16) & 0xff), - (unsigned int)((parts[0] >> 8) & 0xff), - (unsigned int)(parts[0] & 0xff)); + (parts[0] >> 24), + ((parts[0] >> 16) & 0xff), + ((parts[0] >> 8) & 0xff), + (parts[0] & 0xff)); break; case 1: /* a.b -- 8.24 bits */ if((parts[0] > 0xff) || (parts[1] > 0xffffff)) return HOST_NAME; Curl_dyn_reset(host); result = Curl_dyn_addf(host, "%u.%u.%u.%u", - (unsigned int)(parts[0]), - (unsigned int)((parts[1] >> 16) & 0xff), - (unsigned int)((parts[1] >> 8) & 0xff), - (unsigned int)(parts[1] & 0xff)); + (parts[0]), + ((parts[1] >> 16) & 0xff), + ((parts[1] >> 8) & 0xff), + (parts[1] & 0xff)); break; case 2: /* a.b.c -- 8.8.16 bits */ if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xffff)) return HOST_NAME; Curl_dyn_reset(host); result = Curl_dyn_addf(host, "%u.%u.%u.%u", - (unsigned int)(parts[0]), - (unsigned int)(parts[1]), - (unsigned int)((parts[2] >> 8) & 0xff), - (unsigned int)(parts[2] & 0xff)); + (parts[0]), + (parts[1]), + ((parts[2] >> 8) & 0xff), + (parts[2] & 0xff)); break; case 3: /* a.b.c.d -- 8.8.8.8 bits */ if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff) || @@ -674,10 +676,10 @@ static int ipv4_normalize(struct dynbuf *host) return HOST_NAME; Curl_dyn_reset(host); result = Curl_dyn_addf(host, "%u.%u.%u.%u", - (unsigned int)(parts[0]), - (unsigned int)(parts[1]), - (unsigned int)(parts[2]), - (unsigned int)(parts[3])); + (parts[0]), + (parts[1]), + (parts[2]), + (parts[3])); break; } if(result) @@ -1745,11 +1747,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, return CURLUE_BAD_PORT_NUMBER; else { char *tmp; - size_t port; + curl_off_t port; if(Curl_str_number(&part, &port, 0xffff) || *part) /* weirdly provided number, not good! */ return CURLUE_BAD_PORT_NUMBER; - tmp = aprintf("%zd", port); + tmp = aprintf("%" CURL_FORMAT_CURL_OFF_T, port); if(!tmp) return CURLUE_OUT_OF_MEMORY; free(u->port); diff --git a/lib/vquic/.checksrc b/lib/vquic/.checksrc index eff4bc0a3f72..770fad0dfcea 100644 --- a/lib/vquic/.checksrc +++ b/lib/vquic/.checksrc @@ -1,3 +1,5 @@ banfunc strerror banfunc strncpy banfunc sscanf +banfunc strtoul +banfunc strtol diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index 69de5c1a8f58..5937e7d4aca5 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -81,10 +81,10 @@ CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx) #endif #ifdef DEBUGBUILD { - char *p = getenv("CURL_DBG_QUIC_WBLOCK"); + const char *p = getenv("CURL_DBG_QUIC_WBLOCK"); if(p) { - long l = strtol(p, NULL, 10); - if(l >= 0 && l <= 100) + curl_off_t l; + if(!Curl_str_number(&p, &l, 100)) qctx->wblock_percent = (int)l; } } diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 2390967d9121..b5ab7b97d333 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -2871,9 +2871,12 @@ static void sftp_quote_stat(struct Curl_easy *data) /* Now set the new attributes... */ if(strncasecompare(cmd, "chgrp", 5)) { - sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10); + const char *p = sshc->quote_path1; + curl_off_t gid; + (void)Curl_str_number(&p, &gid, UINT_MAX); + sshc->quote_attrs->gid = (uint32_t)gid; if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { + !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chgrp gid not a number"); @@ -2885,10 +2888,9 @@ static void sftp_quote_stat(struct Curl_easy *data) sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; } else if(strncasecompare(cmd, "chmod", 5)) { - mode_t perms; - perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8); - /* permissions are octal */ - if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) { + curl_off_t perms; + const char *p = sshc->quote_path1; + if(Curl_str_octal(&p, &perms, 07777)) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chmod permissions not a number"); @@ -2897,13 +2899,15 @@ static void sftp_quote_stat(struct Curl_easy *data) sshc->actualcode = CURLE_QUOTE_ERROR; return; } - sshc->quote_attrs->permissions = perms; + sshc->quote_attrs->permissions = (mode_t)perms; sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS; } else if(strncasecompare(cmd, "chown", 5)) { - sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10); + const char *p = sshc->quote_path1; + curl_off_t uid; + (void)Curl_str_number(&p, &uid, UINT_MAX); if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { + !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chown uid not a number"); diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 429abac31474..a32483955ce7 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -73,7 +73,7 @@ #include "select.h" #include "warnless.h" #include "curl_path.h" - +#include "strparse.h" #include /* for base64 encoding/decoding */ #include @@ -1368,7 +1368,10 @@ sftp_quote_stat(struct Curl_easy *data, /* Now set the new attributes... */ if(strncasecompare(cmd, "chgrp", 5)) { - sshp->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10); + const char *p = sshc->quote_path1; + curl_off_t gid; + (void)Curl_str_number(&p, &gid, ULONG_MAX); + sshp->quote_attrs.gid = (unsigned long)gid; sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && !sshc->acceptfail) { @@ -1377,17 +1380,22 @@ sftp_quote_stat(struct Curl_easy *data, } } else if(strncasecompare(cmd, "chmod", 5)) { - sshp->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8); - sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; + curl_off_t perms; + const char *p = sshc->quote_path1; /* permissions are octal */ - if(sshp->quote_attrs.permissions == 0 && - !ISDIGIT(sshc->quote_path1[0])) { + if(Curl_str_octal(&p, &perms, 07777)) { failf(data, "Syntax error: chmod permissions not a number"); goto fail; } + + sshp->quote_attrs.permissions = (unsigned long)perms; + sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; } else if(strncasecompare(cmd, "chown", 5)) { - sshp->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10); + const char *p = sshc->quote_path1; + curl_off_t uid; + (void)Curl_str_number(&p, &uid, ULONG_MAX); + sshp->quote_attrs.uid = (unsigned long)uid; sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && !sshc->acceptfail) { diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c index e78a18e71a57..d038ccd26ee8 100644 --- a/lib/vssh/wolfssh.c +++ b/lib/vssh/wolfssh.c @@ -34,7 +34,6 @@ #include "sendf.h" #include "progress.h" #include "curl_path.h" -#include "strtoofft.h" #include "transfer.h" #include "speedcheck.h" #include "select.h" diff --git a/lib/vtls/.checksrc b/lib/vtls/.checksrc index eff4bc0a3f72..770fad0dfcea 100644 --- a/lib/vtls/.checksrc +++ b/lib/vtls/.checksrc @@ -1,3 +1,5 @@ banfunc strerror banfunc strncpy banfunc sscanf +banfunc strtoul +banfunc strtol diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 59fe428abef2..4e6ed052d764 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -55,6 +55,7 @@ #include "multiif.h" #include "version_win32.h" #include "rand.h" +#include "strparse.h" /* The last #include file should be: */ #include "curl_memory.h" @@ -344,9 +345,9 @@ static const struct algo algs[]= { }; static int -get_alg_id_by_name(char *name) +get_alg_id_by_name(const char *name) { - char *nameEnd = strchr(name, ':'); + const char *nameEnd = strchr(name, ':'); size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name); int i; @@ -363,12 +364,13 @@ static CURLcode set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers, ALG_ID *algIds) { - char *startCur = ciphers; + const char *startCur = ciphers; int algCount = 0; while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) { - long alg = strtol(startCur, 0, 0); - if(!alg) + curl_off_t alg; + if(Curl_str_number(&startCur, &alg, INT_MAX) || !alg) alg = get_alg_id_by_name(startCur); + if(alg) algIds[algCount++] = (ALG_ID)alg; else if(!strncmp(startCur, "USE_STRONG_CRYPTO", diff --git a/lib/ws.c b/lib/ws.c index 25d19c69726b..5a52c84ade68 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -39,6 +39,7 @@ #include "transfer.h" #include "select.h" #include "nonblock.h" +#include "strparse.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -778,12 +779,11 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, data->conn->proto.ws = ws; #ifdef DEBUGBUILD { - char *p = getenv("CURL_WS_CHUNK_SIZE"); + const char *p = getenv("CURL_WS_CHUNK_SIZE"); if(p) { - long l = strtol(p, NULL, 10); - if(l > 0 && l <= (1*1024*1024)) { + curl_off_t l; + if(!Curl_str_number(&p, &l, 1*1024*1024)) chunk_size = (size_t)l; - } } } #endif @@ -1032,12 +1032,11 @@ static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws, /* Simulate a blocking send after this chunk has been sent */ bool eagain_next = FALSE; size_t chunk_egain = 0; - char *p = getenv("CURL_WS_CHUNK_EAGAIN"); + const char *p = getenv("CURL_WS_CHUNK_EAGAIN"); if(p) { - long l = strtol(p, NULL, 10); - if(l > 0 && l <= (1*1024*1024)) { + curl_off_t l; + if(!Curl_str_number(&p, &l, 1*1024*1024)) chunk_egain = (size_t)l; - } } #endif diff --git a/projects/generate.bat b/projects/generate.bat index f0e9da841eed..d73b4f0a24c2 100644 --- a/projects/generate.bat +++ b/projects/generate.bat @@ -152,6 +152,8 @@ rem for /f "delims=" %%r in ('dir /b ..\src\*.rc') do call :element %1 src "%%r" %3 ) else if "!var!" == "CURL_SRC_X_C_FILES" ( call :element %1 lib "strtoofft.c" %3 + call :element %1 lib "strparse.c" %3 + call :element %1 lib "strcase.c" %3 call :element %1 lib "timediff.c" %3 call :element %1 lib "nonblock.c" %3 call :element %1 lib "warnless.c" %3 @@ -163,6 +165,8 @@ rem call :element %1 lib "config-win32.h" %3 call :element %1 lib "curl_setup.h" %3 call :element %1 lib "strtoofft.h" %3 + call :element %1 lib "strparse.h" %3 + call :element %1 lib "strcase.h" %3 call :element %1 lib "timediff.h" %3 call :element %1 lib "nonblock.h" %3 call :element %1 lib "warnless.h" %3 diff --git a/src/Makefile.inc b/src/Makefile.inc index 404e1aae3990..b2d0d22cb3e3 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -42,6 +42,8 @@ CURLX_CFILES = \ ../lib/dynbuf.c \ ../lib/nonblock.c \ ../lib/strtoofft.c \ + ../lib/strparse.c \ + ../lib/strcase.c \ ../lib/timediff.c \ ../lib/version_win32.c \ ../lib/warnless.c @@ -53,6 +55,8 @@ CURLX_HFILES = \ ../lib/dynbuf.h \ ../lib/nonblock.h \ ../lib/strtoofft.h \ + ../lib/strparse.h \ + ../lib/strcase.h \ ../lib/timediff.h \ ../lib/version_win32.h \ ../lib/warnless.h diff --git a/tests/data/test1664 b/tests/data/test1664 index 7ae67f0f2b74..0c52b11afb70 100644 --- a/tests/data/test1664 +++ b/tests/data/test1664 @@ -97,9 +97,9 @@ Curl_str_number 10: (" 123") 8, [0] line 0 11: ("") 8, [0] line 0 Curl_str_number / max -0: ("9223372036854775808") 0, [9223372036854775808] line 19 -1: ("9223372036854775809") 0, [9223372036854775809] line 19 -2: ("18446744073709551615") 0, [18446744073709551615] line 20 +0: ("9223372036854775807") 0, [9223372036854775807] line 19 +1: ("9223372036854775808") 7, [0] line 18 +2: ("18446744073709551615") 7, [0] line 19 3: ("18446744073709551616") 7, [0] line 19 4: ("18446744073709551617") 7, [0] line 19 Curl_str_newline @@ -115,6 +115,38 @@ Curl_str_newline 8: (" ") 0, line 1 9: ("") 6, line 0 +Curl_str_hex +0: ("1") 0, [1] line 1 +1: ("1000") 0, [4096] line 4 +2: ("1234") 0, [4660] line 4 +3: ("1235") 0, [4661] line 4 +4: ("1236") 1, [0] line 3 +5: ("01234") 0, [4660] line 5 +6: ("00000000000000000000000000001234") 0, [4660] line 32 +7: ("0123 345") 0, [291] line 4 +8: ("0123O345") 0, [291] line 4 +9: ("-12") 8, [0] line 0 +10: (" 123") 8, [0] line 0 +11: ("") 8, [0] line 0 +Curl_str_octal +0: ("1") 0, [1] line 1 +1: ("1000") 0, [512] line 4 +2: ("1234") 0, [668] line 4 +3: ("1235") 0, [669] line 4 +4: ("1236") 1, [0] line 3 +5: ("01234") 0, [668] line 5 +6: ("00000000000000000000000000001234") 0, [668] line 32 +7: ("0123 345") 0, [83] line 4 +8: ("0123O345") 0, [83] line 4 +9: ("-12") 8, [0] line 0 +10: (" 123") 8, [0] line 0 +11: ("") 8, [0] line 0 +Curl_str_octal / max +0: ("777777777777777777777") 0, [9223372036854775807] line 21 +1: ("1000000000000000000000") 7, [0] line 21 +Curl_str_hex / max +0: ("7FFFFFFFFFFFFFFF") 0, [9223372036854775807] line 16 +1: ("8000000000000000") 7, [0] line 15 diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index bcd8cae5e8a4..7927b9c7e799 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -29,6 +29,8 @@ CURLX_SRCS = \ ../../lib/mprintf.c \ ../../lib/nonblock.c \ ../../lib/strtoofft.c \ + ../../lib/strparse.c \ + ../../lib/strequal.c \ ../../lib/warnless.c \ ../../lib/timediff.c \ ../../lib/dynbuf.c \ @@ -41,10 +43,12 @@ CURLX_HDRS = \ ../../lib/curlx.h \ ../../lib/nonblock.h \ ../../lib/strtoofft.h \ + ../../lib/strcase.h \ ../../lib/warnless.h \ ../../lib/timediff.h \ ../../lib/curl_ctype.h \ ../../lib/dynbuf.h \ + ../../lib/strcase.h \ ../../lib/strdup.h \ ../../lib/curl_get_line.h \ ../../lib/curl_multibyte.h diff --git a/tests/unit/unit1664.c b/tests/unit/unit1664.c index 0c22f9164ad0..4fbe89da13ee 100644 --- a/tests/unit/unit1664.c +++ b/tests/unit/unit1664.c @@ -196,7 +196,7 @@ UNITTEST_START }; printf("Curl_str_number\n"); for(i = 0; nums[i]; i++) { - size_t num; + curl_off_t num; const char *line = nums[i]; const char *orgline = line; int rc = Curl_str_number(&line, &num, 1235); @@ -206,10 +206,10 @@ UNITTEST_START } { - /* SIZE_T_MAX is typically 18446744073709551615 */ + /* CURL_OFF_T is typically 9223372036854775807 */ static const char *nums[] = { - "9223372036854775808", /* 2^63 */ - "9223372036854775809", /* 2^63 + 1 */ + "9223372036854775807", /* 2^63 -1 */ + "9223372036854775808", /* 2^63 */ "18446744073709551615", /* 2^64 - 1 */ "18446744073709551616", /* 2^64 */ "18446744073709551617", /* 2^64 + 1 */ @@ -217,11 +217,11 @@ UNITTEST_START }; printf("Curl_str_number / max\n"); for(i = 0; nums[i]; i++) { - size_t num; + curl_off_t num; const char *line = nums[i]; const char *orgline = line; - int rc = Curl_str_number(&line, &num, SIZE_T_MAX); - printf("%u: (\"%s\") %d, [%zu] line %d\n", + int rc = Curl_str_number(&line, &num, CURL_OFF_T_MAX); + printf("%u: (\"%s\") %d, [%" CURL_FORMAT_CURL_OFF_T "] line %d\n", i, orgline, rc, num, (int)(line - orgline)); } } @@ -250,5 +250,95 @@ UNITTEST_START } } + { + static const char *nums[] = { + "1", + "1000", + "1234", + "1235", + "1236", + "01234", + "00000000000000000000000000001234", + "0123 345", + "0123O345", + "-12", + " 123", + "", + NULL + }; + printf("Curl_str_hex\n"); + for(i = 0; nums[i]; i++) { + curl_off_t num; + const char *line = nums[i]; + const char *orgline = line; + int rc = Curl_str_hex(&line, &num, 0x1235); + printf("%u: (\"%s\") %d, [%u] line %d\n", + i, orgline, rc, (int)num, (int)(line - orgline)); + } + } + + { + static const char *nums[] = { + "1", + "1000", + "1234", + "1235", + "1236", + "01234", + "00000000000000000000000000001234", + "0123 345", + "0123O345", + "-12", + " 123", + "", + NULL + }; + printf("Curl_str_octal\n"); + for(i = 0; nums[i]; i++) { + curl_off_t num; + const char *line = nums[i]; + const char *orgline = line; + int rc = Curl_str_octal(&line, &num, 01235); + printf("%u: (\"%s\") %d, [%u] line %d\n", + i, orgline, rc, (int)num, (int)(line - orgline)); + } + } + + { + /* CURL_OFF_T is typically 2^63-1 */ + static const char *nums[] = { + "777777777777777777777", /* 2^63 -1 */ + "1000000000000000000000", /* 2^63 */ + NULL + }; + printf("Curl_str_octal / max\n"); + for(i = 0; nums[i]; i++) { + curl_off_t num; + const char *line = nums[i]; + const char *orgline = line; + int rc = Curl_str_octal(&line, &num, CURL_OFF_T_MAX); + printf("%u: (\"%s\") %d, [%" CURL_FORMAT_CURL_OFF_T "] line %d\n", + i, orgline, rc, num, (int)(line - orgline)); + } + } + + { + /* CURL_OFF_T is typically 2^63-1 */ + static const char *nums[] = { + "7FFFFFFFFFFFFFFF", /* 2^63 -1 */ + "8000000000000000", /* 2^63 */ + NULL + }; + printf("Curl_str_hex / max\n"); + for(i = 0; nums[i]; i++) { + curl_off_t num; + const char *line = nums[i]; + const char *orgline = line; + int rc = Curl_str_hex(&line, &num, CURL_OFF_T_MAX); + printf("%u: (\"%s\") %d, [%" CURL_FORMAT_CURL_OFF_T "] line %d\n", + i, orgline, rc, num, (int)(line - orgline)); + } + } + } UNITTEST_STOP diff --git a/winbuild/MakefileBuild.vc b/winbuild/MakefileBuild.vc index 84863f8dd1c7..06fec81ee733 100644 --- a/winbuild/MakefileBuild.vc +++ b/winbuild/MakefileBuild.vc @@ -692,6 +692,8 @@ CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP) CURL_FROM_LIBCURL=\ $(CURL_DIROBJ)\nonblock.obj \ $(CURL_DIROBJ)\strtoofft.obj \ + $(CURL_DIROBJ)\strparse.obj \ + $(CURL_DIROBJ)\strcase.obj \ $(CURL_DIROBJ)\warnless.obj \ $(CURL_DIROBJ)\curl_get_line.obj \ $(CURL_DIROBJ)\curl_multibyte.obj \ @@ -718,6 +720,10 @@ $(CURL_DIROBJ)\nonblock.obj: ../lib/nonblock.c $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/nonblock.c $(CURL_DIROBJ)\strtoofft.obj: ../lib/strtoofft.c $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/strtoofft.c +$(CURL_DIROBJ)\strparse.obj: ../lib/strparse.c + $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/strparse.c +$(CURL_DIROBJ)\strcase.obj: ../lib/strcase.c + $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/strcase.c $(CURL_DIROBJ)\warnless.obj: ../lib/warnless.c $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/warnless.c $(CURL_DIROBJ)\curl_get_line.obj: ../lib/curl_get_line.c