Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 
     23 #include "curl_setup.h"
     24 
     25 #include "strtoofft.h"
     26 
     27 /*
     28  * NOTE:
     29  *
     30  * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
     31  * could use in case strtoll() doesn't exist...  See
     32  * http://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
     33  */
     34 
     35 #ifdef NEED_CURL_STRTOLL
     36 
     37 /* Range tests can be used for alphanum decoding if characters are consecutive,
     38    like in ASCII. Else an array is scanned. Determine this condition now. */
     39 
     40 #if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25
     41 
     42 #define NO_RANGE_TEST
     43 
     44 static const char valchars[] =
     45             "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     46 #endif
     47 
     48 static int get_char(char c, int base);
     49 
     50 /**
     51  * Emulated version of the strtoll function.  This extracts a long long
     52  * value from the given input string and returns it.
     53  */
     54 curl_off_t
     55 curlx_strtoll(const char *nptr, char **endptr, int base)
     56 {
     57   char *end;
     58   int is_negative = 0;
     59   int overflow;
     60   int i;
     61   curl_off_t value = 0;
     62   curl_off_t newval;
     63 
     64   /* Skip leading whitespace. */
     65   end = (char *)nptr;
     66   while(ISSPACE(end[0])) {
     67     end++;
     68   }
     69 
     70   /* Handle the sign, if any. */
     71   if(end[0] == '-') {
     72     is_negative = 1;
     73     end++;
     74   }
     75   else if(end[0] == '+') {
     76     end++;
     77   }
     78   else if(end[0] == '\0') {
     79     /* We had nothing but perhaps some whitespace -- there was no number. */
     80     if(endptr) {
     81       *endptr = end;
     82     }
     83     return 0;
     84   }
     85 
     86   /* Handle special beginnings, if present and allowed. */
     87   if(end[0] == '0' && end[1] == 'x') {
     88     if(base == 16 || base == 0) {
     89       end += 2;
     90       base = 16;
     91     }
     92   }
     93   else if(end[0] == '0') {
     94     if(base == 8 || base == 0) {
     95       end++;
     96       base = 8;
     97     }
     98   }
     99 
    100   /* Matching strtol, if the base is 0 and it doesn't look like
    101    * the number is octal or hex, we assume it's base 10.
    102    */
    103   if(base == 0) {
    104     base = 10;
    105   }
    106 
    107   /* Loop handling digits. */
    108   value = 0;
    109   overflow = 0;
    110   for(i = get_char(end[0], base);
    111       i != -1;
    112       end++, i = get_char(end[0], base)) {
    113     newval = base * value + i;
    114     if(newval < value) {
    115       /* We've overflowed. */
    116       overflow = 1;
    117       break;
    118     }
    119     else
    120       value = newval;
    121   }
    122 
    123   if(!overflow) {
    124     if(is_negative) {
    125       /* Fix the sign. */
    126       value *= -1;
    127     }
    128   }
    129   else {
    130     if(is_negative)
    131       value = CURL_OFF_T_MIN;
    132     else
    133       value = CURL_OFF_T_MAX;
    134 
    135     SET_ERRNO(ERANGE);
    136   }
    137 
    138   if(endptr)
    139     *endptr = end;
    140 
    141   return value;
    142 }
    143 
    144 /**
    145  * Returns the value of c in the given base, or -1 if c cannot
    146  * be interpreted properly in that base (i.e., is out of range,
    147  * is a null, etc.).
    148  *
    149  * @param c     the character to interpret according to base
    150  * @param base  the base in which to interpret c
    151  *
    152  * @return  the value of c in base, or -1 if c isn't in range
    153  */
    154 static int get_char(char c, int base)
    155 {
    156 #ifndef NO_RANGE_TEST
    157   int value = -1;
    158   if(c <= '9' && c >= '0') {
    159     value = c - '0';
    160   }
    161   else if(c <= 'Z' && c >= 'A') {
    162     value = c - 'A' + 10;
    163   }
    164   else if(c <= 'z' && c >= 'a') {
    165     value = c - 'a' + 10;
    166   }
    167 #else
    168   const char *cp;
    169   int value;
    170 
    171   cp = memchr(valchars, c, 10 + 26 + 26);
    172 
    173   if(!cp)
    174     return -1;
    175 
    176   value = cp - valchars;
    177 
    178   if(value >= 10 + 26)
    179     value -= 26;                /* Lowercase. */
    180 #endif
    181 
    182   if(value >= base) {
    183     value = -1;
    184   }
    185 
    186   return value;
    187 }
    188 #endif  /* Only present if we need strtoll, but don't have it. */
    189