]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
strparse: switch to curl_off_t as base data type
authorDaniel Stenberg <daniel@haxx.se>
Fri, 14 Feb 2025 10:29:08 +0000 (11:29 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Sat, 15 Feb 2025 20:58:48 +0000 (21:58 +0100)
- 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

46 files changed:
lib/.checksrc
lib/Makefile.inc
lib/altsvc.c
lib/cf-socket.c
lib/cfilters.c
lib/conncache.c
lib/cookie.c
lib/curl_ctype.h
lib/curl_range.c
lib/ftp.c
lib/ftplistparser.c
lib/getinfo.c
lib/hostip.c
lib/hsts.c
lib/http.c
lib/imap.c
lib/ldap.c
lib/openldap.c
lib/parsedate.c
lib/request.c
lib/rtsp.c
lib/smtp.c
lib/strcase.c
lib/strequal.c [new file with mode: 0644]
lib/strparse.c
lib/strparse.h
lib/strtoofft.c
lib/strtoofft.h
lib/telnet.c
lib/tftp.c
lib/url.c
lib/urlapi.c
lib/vquic/.checksrc
lib/vquic/vquic.c
lib/vssh/libssh.c
lib/vssh/libssh2.c
lib/vssh/wolfssh.c
lib/vtls/.checksrc
lib/vtls/schannel.c
lib/ws.c
projects/generate.bat
src/Makefile.inc
tests/data/test1664
tests/server/Makefile.inc
tests/unit/unit1664.c
winbuild/MakefileBuild.vc

index 3985707fd9e44c1efb1d6e7f89c8b702e1f5a5a1..3d4af2313b62c6dd54dcf504b87e2fd8b1326107 100644 (file)
@@ -3,3 +3,5 @@ banfunc strncpy
 banfunc sscanf
 banfunc snprintf
 banfunc vsnprint
+banfunc strtoul
+banfunc strtol
index 25c6df84ecb9448473aba9381b9cfb4c72e423b4..0e6724bcdbe074730311e1e004ff1e481ee8c9ab 100644 (file)
@@ -226,6 +226,7 @@ LIB_CFILES =         \
   splay.c            \
   strcase.c          \
   strdup.c           \
+  strequal.c         \
   strerror.c         \
   strparse.c         \
   strtok.c           \
index a958ea58117b050f28e2ea42a9b16b1948092e17..c7449ab1068b99e437beb5230ce0cf7b4be9e55c 100644 (file)
@@ -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(&timestr, &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))
index b7262b19e9e3db935b5b145f88e76a9d85df88b8..abd485a971018f9f2db56f9d5a4b1a7c25a4fb57 100644 (file)
@@ -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;
     }
   }
index 6a894e8ce6e9e79db69737dc2996c4abec842eec..91f7325c3834f2a002270bf03f4c14b7de785caf 100644 (file)
@@ -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
index b8a0515276d1853b1bc715b6a9ed6233b16ed1f8..2df29d9385fd8cbe4a3a6f378719c9ae03d7e005 100644 (file)
@@ -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;
     }
   }
index 6fdabfd7914ffa4009e186af10c20f3f3110ea98..f523bf5ed093d40b551e18fb50eddc55b7052d87 100644 (file)
@@ -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);
index b70acf3c5a66174381ec361f06527ad29e5afd74..48c3c37c359c75e75b6f919e9b32b1a41d20b9dc 100644 (file)
@@ -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'))
index 49fb5f07783dfe70e07a225ddc275d4b5f95f666..868c1e054be19e8f6ea42b43fe936a40265d306b 100644 (file)
@@ -26,7 +26,7 @@
 #include <curl/curl.h>
 #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)
  */
 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));
index 2210d8145f866ddcd079bed8620508a822336d59..e38ee1b88d559e14542874e1f66fc3d1feda6730 100644 (file)
--- 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;
         }
       }
     }
index b4c0574785ae1f7faba4cd9af1d517f46685aba6..8ca46998f565c1d245c7d8acdacb86f8a2b98d32 100644 (file)
@@ -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)) {
index ae6b3b8aa0f0e7597c54003ca73779fc9d0ed314..9b5912bac488ca40ce9b842d90972cf9cfe08ff0 100644 (file)
 
 #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(&timestr, &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(&timestr, &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(&timestr, &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(&timestr, &val, CURL_OFF_T_MAX);
+
     switch(info) {
     case CURLINFO_TOTAL_TIME:
     case CURLINFO_NAMELOOKUP_TIME:
index d14476ccaeb6392937d9f98ace029970875a7ba2..4dbedfb0120691b271524ace87fcd36f9400ad4d 100644 (file)
@@ -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 @@ err:
       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 @@ err:
         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;
       }
     }
index 1dcaf026ac920f4df7d9f83937ef7aa0464f08fd..1c729d94cbd5d9599b9f160ffb8828afbbf2109d 100644 (file)
@@ -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"
 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(&timestr, &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;
index 9e15afe46a1def3bca7a44376ea42665cc6ea221..8010b4d92d05cfcefe1ab75cd14ca8abdf8a1c73 100644 (file)
@@ -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 */
index c15e96e7f85d1caf40fe0a075758441f19794777..0672b32af50ba1ff67d78de704ba52d1be8409cb 100644 (file)
@@ -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;
   }
 
index 77bd9fba67afc0d343cf453ef1224bc84856cfa4..dfabf55d118a4bb7d445340985e3f1866951bd0c 100644 (file)
@@ -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;
index 22e5bdd27901935ee464365dbc99ef62e73439de..13f8abf191309adae0d6222413ec8f2b22c3c0a3 100644 (file)
@@ -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);
index 030a3c59b822ea672ad8ffa8c010193d149a0bc1..1795d6df6cdbd3056c00162b681ee2f426eb108a 100644 (file)
@@ -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))
index d5f04e9f1d6f692189d55fc358a457975c43ea59..6e98879c3178e885ef2175f5b36d43d037bc6ae4 100644 (file)
@@ -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
index 253c4551a0737c64f27c002e0458d1b7aa069979..652734ee2d2f4282c7cf86076dbfecd6a8edc03f 100644 (file)
@@ -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;
index e5ad4f56b1a05f41812220c32fcf6dc197cadeb0..ffb23a6a8630f3d26595be4ee8bb2a51b3a961b9 100644 (file)
@@ -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));
index 7ae0929af3bfc324bf0c2a2a01fd019dd8b822ae..841949ec5e9c26c755ebde1bc35e8f9cb54f6980 100644 (file)
@@ -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 (file)
index 0000000..d1ba915
--- /dev/null
@@ -0,0 +1,88 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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 <curl/curl.h>
+#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;
+}
index c540148c9a30288ac56c1978615b4cfe2b26155c..6730b96d1b298d920a42f6f75a2e9783d0d890f2 100644 (file)
@@ -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)
index 77171f59a1f49636704c6532d30d143834160d57..7ade183ec22bc7d654d7c721816e9ced421eb3af 100644 (file)
@@ -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 */
index 05536c18261370d576bce845ea07ed5b63ada92d..5a7f058f96625af18a0195ee689dcde031a4df84 100644 (file)
  *
  ***************************************************************************/
 
-#include <errno.h>
 #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;
 
index 71808b719c9b3195973ce98c9b7d7e4b30b06a5c..051ab3064d8d3a53904100601f9c0591148d4e85 100644 (file)
 
 #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 */
index bd85b119ec59558e06b5e4a4e6c32c6734e503fe..97972482bd139b07c6de1a77a3cc78949e66feaa 100644 (file)
@@ -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)) {
index 7f1eef518827fe6c2d70aedbe52f9617d50002fc..5fb8f3157e0beff2f544415827ab96ce6c296570 100644 (file)
@@ -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);
       }
     }
index 564971d68e9388370b62ee1503bb45d52bff65f7..cdca4b707228bbecb293176feec55bbf469acbda 100644 (file)
--- 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;
       }
index 33684ccee175e9ee302fc20dff2a82bef5460a68..a3aac4f2fff771fc4391a3c283ccaef924acdd7d 100644 (file)
@@ -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);
index eff4bc0a3f72c5bba440cf9b9eebff2ae4bd7df9..770fad0dfcead92e7b4b09fefa07dc383f3c3fae 100644 (file)
@@ -1,3 +1,5 @@
 banfunc strerror
 banfunc strncpy
 banfunc sscanf
+banfunc strtoul
+banfunc strtol
index 69de5c1a8f58c5a62030bcc463d10d9faa34fd8b..5937e7d4aca5e8d2e71798ac0742795bf813fe69 100644 (file)
@@ -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;
     }
   }
index 2390967d9121f0da486cd53c4b62cb0bdb8e62bd..b5ab7b97d33330eb23b325b1488cd3bd8a8701e1 100644 (file)
@@ -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");
index 429abac3147404bc1a58a44fbf1dea999fcd9fda..a32483955ce78056f0ccc6ea59f7e129ac02c55d 100644 (file)
@@ -73,7 +73,7 @@
 #include "select.h"
 #include "warnless.h"
 #include "curl_path.h"
-
+#include "strparse.h"
 #include <curl_base64.h> /* for base64 encoding/decoding */
 #include <curl_sha256.h>
 
@@ -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) {
index e78a18e71a57a894fdaa74ad8615bf191cb91a3e..d038ccd26ee8aaec84c331e23f44f09e85360f56 100644 (file)
@@ -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"
index eff4bc0a3f72c5bba440cf9b9eebff2ae4bd7df9..770fad0dfcead92e7b4b09fefa07dc383f3c3fae 100644 (file)
@@ -1,3 +1,5 @@
 banfunc strerror
 banfunc strncpy
 banfunc sscanf
+banfunc strtoul
+banfunc strtol
index 59fe428abef26d05de38fcbe54b6bdc2045f9fe7..4e6ed052d7645adbf8932d8f7c5f7bf92dc73de8 100644 (file)
@@ -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",
index 25d19c69726bda8efb99f94ea33502914fb5be43..5a52c84ade6836fc037597a0f68ef2efc36848fe 100644 (file)
--- 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
 
index f0e9da841eed12dc78b3b7229f4f0a34d729c413..d73b4f0a24c2c5cb057aa62109a2de12d53320a3 100644 (file)
@@ -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
index 404e1aae3990c6cd1d7c63fac3c294dfaddd7214..b2d0d22cb3e3f3dbaea6e473e322a1ea613ebafd 100644 (file)
@@ -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
index 7ae67f0f2b741225774024e21eab6b64ee31391a..0c52b11afb7035a3746be410f2758977e015908e 100644 (file)
@@ -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: ("\r
 ") 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
 </stdout>
 </verify>
 </testcase>
index bcd8cae5e8a4900645036b9a32775e6c26d240fc..7927b9c7e799641bcd26a1a7c8c5c526180f5551 100644 (file)
@@ -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
index 0c22f9164ad04c0f83944d0f1ef485e78f878955..4fbe89da13ee7e1c9ef7ecce10890d6979c06636 100644 (file)
@@ -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
index 84863f8dd1c75a876d5beca1f2394b12bc11577f..06fec81ee73353eb3ad858e497dfa087326ea32e 100644 (file)
@@ -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