quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

strparse.c (8565B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@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.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  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 #include "strparse.h"
     26 
     27 #ifndef WITHOUT_LIBCURL
     28 #include <curl/curl.h>  /* for curl_strnequal() */
     29 #endif
     30 
     31 void curlx_str_init(struct Curl_str *out)
     32 {
     33   out->str = NULL;
     34   out->len = 0;
     35 }
     36 
     37 void curlx_str_assign(struct Curl_str *out, const char *str, size_t len)
     38 {
     39   out->str = str;
     40   out->len = len;
     41 }
     42 
     43 /* Get a word until the first DELIM or end of string. At least one byte long.
     44    return non-zero on error */
     45 int curlx_str_until(const char **linep, struct Curl_str *out,
     46                     const size_t max, char delim)
     47 {
     48   const char *s = *linep;
     49   size_t len = 0;
     50   DEBUGASSERT(linep && *linep && out && max && delim);
     51 
     52   curlx_str_init(out);
     53   while(*s && (*s != delim)) {
     54     s++;
     55     if(++len > max) {
     56       return STRE_BIG;
     57     }
     58   }
     59   if(!len)
     60     return STRE_SHORT;
     61   out->str = *linep;
     62   out->len = len;
     63   *linep = s; /* point to the first byte after the word */
     64   return STRE_OK;
     65 }
     66 
     67 /* Get a word until the first space or end of string. At least one byte long.
     68    return non-zero on error */
     69 int curlx_str_word(const char **linep, struct Curl_str *out,
     70                    const size_t max)
     71 {
     72   return curlx_str_until(linep, out, max, ' ');
     73 }
     74 
     75 /* Get a word until a newline byte or end of string. At least one byte long.
     76    return non-zero on error */
     77 int curlx_str_untilnl(const char **linep, struct Curl_str *out,
     78                       const size_t max)
     79 {
     80   const char *s = *linep;
     81   size_t len = 0;
     82   DEBUGASSERT(linep && *linep && out && max);
     83 
     84   curlx_str_init(out);
     85   while(*s && !ISNEWLINE(*s)) {
     86     s++;
     87     if(++len > max)
     88       return STRE_BIG;
     89   }
     90   if(!len)
     91     return STRE_SHORT;
     92   out->str = *linep;
     93   out->len = len;
     94   *linep = s; /* point to the first byte after the word */
     95   return STRE_OK;
     96 }
     97 
     98 
     99 /* Get a "quoted" word. No escaping possible.
    100    return non-zero on error */
    101 int curlx_str_quotedword(const char **linep, struct Curl_str *out,
    102                          const size_t max)
    103 {
    104   const char *s = *linep;
    105   size_t len = 0;
    106   DEBUGASSERT(linep && *linep && out && max);
    107 
    108   curlx_str_init(out);
    109   if(*s != '\"')
    110     return STRE_BEGQUOTE;
    111   s++;
    112   while(*s && (*s != '\"')) {
    113     s++;
    114     if(++len > max)
    115       return STRE_BIG;
    116   }
    117   if(*s != '\"')
    118     return STRE_ENDQUOTE;
    119   out->str = (*linep) + 1;
    120   out->len = len;
    121   *linep = s + 1;
    122   return STRE_OK;
    123 }
    124 
    125 /* Advance over a single character.
    126    return non-zero on error */
    127 int curlx_str_single(const char **linep, char byte)
    128 {
    129   DEBUGASSERT(linep && *linep);
    130   if(**linep != byte)
    131     return STRE_BYTE;
    132   (*linep)++; /* move over it */
    133   return STRE_OK;
    134 }
    135 
    136 /* Advance over a single space.
    137    return non-zero on error */
    138 int curlx_str_singlespace(const char **linep)
    139 {
    140   return curlx_str_single(linep, ' ');
    141 }
    142 
    143 /* given an ASCII character and max ascii, return TRUE if valid */
    144 #define valid_digit(x,m) \
    145   (((x) >= '0') && ((x) <= m) && Curl_hexasciitable[(x)-'0'])
    146 
    147 /* We use 16 for the zero index (and the necessary bitwise AND in the loop)
    148    to be able to have a non-zero value there to make valid_digit() able to
    149    use the info */
    150 const unsigned char Curl_hexasciitable[] = {
    151   16, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* 0x30: 0 - 9 */
    152   0, 0, 0, 0, 0, 0, 0,
    153   10, 11, 12, 13, 14, 15,        /* 0x41: A - F */
    154   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    155   10, 11, 12, 13, 14, 15         /* 0x61: a - f */
    156 };
    157 
    158 /* no support for 0x prefix nor leading spaces */
    159 static int str_num_base(const char **linep, curl_off_t *nump, curl_off_t max,
    160                         int base) /* 8, 10 or 16, nothing else */
    161 {
    162   curl_off_t num = 0;
    163   const char *p;
    164   int m = (base == 10) ? '9' :   /* the largest digit possible */
    165     (base == 16) ? 'f' : '7';
    166   DEBUGASSERT(linep && *linep && nump);
    167   DEBUGASSERT((base == 8) || (base == 10) || (base == 16));
    168   DEBUGASSERT(max >= 0); /* mostly to catch SIZE_T_MAX, which is too large */
    169   *nump = 0;
    170   p = *linep;
    171   if(!valid_digit(*p, m))
    172     return STRE_NO_NUM;
    173   if(max < base) {
    174     /* special-case low max scenario because check needs to be different */
    175     do {
    176       int n = Curl_hexval(*p++);
    177       num = num * base + n;
    178       if(num > max)
    179         return STRE_OVERFLOW;
    180     } while(valid_digit(*p, m));
    181   }
    182   else {
    183     do {
    184       int n = Curl_hexval(*p++);
    185       if(num > ((max - n) / base))
    186         return STRE_OVERFLOW;
    187       num = num * base + n;
    188     } while(valid_digit(*p, m));
    189   }
    190   *nump = num;
    191   *linep = p;
    192   return STRE_OK;
    193 }
    194 
    195 /* Get an unsigned decimal number with no leading space or minus. Leading
    196    zeroes are accepted. return non-zero on error */
    197 int curlx_str_number(const char **linep, curl_off_t *nump, curl_off_t max)
    198 {
    199   return str_num_base(linep, nump, max, 10);
    200 }
    201 
    202 /* Get an unsigned hexadecimal number with no leading space or minus and no
    203    "0x" support. Leading zeroes are accepted. return non-zero on error */
    204 int curlx_str_hex(const char **linep, curl_off_t *nump, curl_off_t max)
    205 {
    206   return str_num_base(linep, nump, max, 16);
    207 }
    208 
    209 /* Get an unsigned octal number with no leading space or minus and no "0"
    210    prefix support. Leading zeroes are accepted. return non-zero on error */
    211 int curlx_str_octal(const char **linep, curl_off_t *nump, curl_off_t max)
    212 {
    213   return str_num_base(linep, nump, max, 8);
    214 }
    215 
    216 /*
    217  * Parse a positive number up to 63-bit number written in ASCII. Skip leading
    218  * blanks. No support for prefixes.
    219  */
    220 int curlx_str_numblanks(const char **str, curl_off_t *num)
    221 {
    222   curlx_str_passblanks(str);
    223   return curlx_str_number(str, num, CURL_OFF_T_MAX);
    224 }
    225 
    226 /* CR or LF
    227    return non-zero on error */
    228 int curlx_str_newline(const char **linep)
    229 {
    230   DEBUGASSERT(linep && *linep);
    231   if(ISNEWLINE(**linep)) {
    232     (*linep)++;
    233     return STRE_OK; /* yessir */
    234   }
    235   return STRE_NEWLINE;
    236 }
    237 
    238 #ifndef WITHOUT_LIBCURL
    239 /* case insensitive compare that the parsed string matches the given string.
    240    Returns non-zero on match. */
    241 int curlx_str_casecompare(struct Curl_str *str, const char *check)
    242 {
    243   size_t clen = check ? strlen(check) : 0;
    244   return ((str->len == clen) && curl_strnequal(str->str, check, clen));
    245 }
    246 #endif
    247 
    248 /* case sensitive string compare. Returns non-zero on match. */
    249 int curlx_str_cmp(struct Curl_str *str, const char *check)
    250 {
    251   if(check) {
    252     size_t clen = strlen(check);
    253     return ((str->len == clen) && !strncmp(str->str, check, clen));
    254   }
    255   return !!(str->len);
    256 }
    257 
    258 /* Trim off 'num' number of bytes from the beginning (left side) of the
    259    string. If 'num' is larger than the string, return error. */
    260 int curlx_str_nudge(struct Curl_str *str, size_t num)
    261 {
    262   if(num <= str->len) {
    263     str->str += num;
    264     str->len -= num;
    265     return STRE_OK;
    266   }
    267   return STRE_OVERFLOW;
    268 }
    269 
    270 /* Get the following character sequence that consists only of bytes not
    271    present in the 'reject' string. Like strcspn(). */
    272 int curlx_str_cspn(const char **linep, struct Curl_str *out,
    273                    const char *reject)
    274 {
    275   const char *s = *linep;
    276   size_t len;
    277   DEBUGASSERT(linep && *linep);
    278 
    279   len = strcspn(s, reject);
    280   if(len) {
    281     out->str = s;
    282     out->len = len;
    283     *linep = &s[len];
    284     return STRE_OK;
    285   }
    286   curlx_str_init(out);
    287   return STRE_SHORT;
    288 }
    289 
    290 /* remove ISBLANK()s from both ends of the string */
    291 void curlx_str_trimblanks(struct Curl_str *out)
    292 {
    293   while(out->len && ISBLANK(*out->str))
    294     curlx_str_nudge(out, 1);
    295 
    296   /* trim trailing spaces and tabs */
    297   while(out->len && ISBLANK(out->str[out->len - 1]))
    298     out->len--;
    299 }
    300 
    301 /* increase the pointer until it has moved over all blanks */
    302 void curlx_str_passblanks(const char **linep)
    303 {
    304   while(ISBLANK(**linep))
    305     (*linep)++; /* move over it */
    306 }