summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/curlx/strparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/curlx/strparse.c')
-rw-r--r--libs/libcurl/src/curlx/strparse.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/libs/libcurl/src/curlx/strparse.c b/libs/libcurl/src/curlx/strparse.c
new file mode 100644
index 0000000000..b92959ec2c
--- /dev/null
+++ b/libs/libcurl/src/curlx/strparse.c
@@ -0,0 +1,303 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "strparse.h"
+#include "../strcase.h"
+
+void curlx_str_init(struct Curl_str *out)
+{
+ out->str = NULL;
+ out->len = 0;
+}
+
+void curlx_str_assign(struct Curl_str *out, const char *str, size_t len)
+{
+ out->str = str;
+ out->len = len;
+}
+
+/* Get a word until the first DELIM or end of string. At least one byte long.
+ return non-zero on error */
+int curlx_str_until(const char **linep, struct Curl_str *out,
+ const size_t max, char delim)
+{
+ const char *s = *linep;
+ size_t len = 0;
+ DEBUGASSERT(linep && *linep && out && max && delim);
+
+ curlx_str_init(out);
+ while(*s && (*s != delim)) {
+ s++;
+ if(++len > max) {
+ return STRE_BIG;
+ }
+ }
+ if(!len)
+ return STRE_SHORT;
+ out->str = *linep;
+ out->len = len;
+ *linep = s; /* point to the first byte after the word */
+ return STRE_OK;
+}
+
+/* Get a word until the first space or end of string. At least one byte long.
+ return non-zero on error */
+int curlx_str_word(const char **linep, struct Curl_str *out,
+ const size_t max)
+{
+ return curlx_str_until(linep, out, max, ' ');
+}
+
+/* Get a word until a newline byte or end of string. At least one byte long.
+ return non-zero on error */
+int curlx_str_untilnl(const char **linep, struct Curl_str *out,
+ const size_t max)
+{
+ const char *s = *linep;
+ size_t len = 0;
+ DEBUGASSERT(linep && *linep && out && max);
+
+ curlx_str_init(out);
+ while(*s && !ISNEWLINE(*s)) {
+ s++;
+ if(++len > max)
+ return STRE_BIG;
+ }
+ if(!len)
+ return STRE_SHORT;
+ out->str = *linep;
+ out->len = len;
+ *linep = s; /* point to the first byte after the word */
+ return STRE_OK;
+}
+
+
+/* Get a "quoted" word. No escaping possible.
+ return non-zero on error */
+int curlx_str_quotedword(const char **linep, struct Curl_str *out,
+ const size_t max)
+{
+ const char *s = *linep;
+ size_t len = 0;
+ DEBUGASSERT(linep && *linep && out && max);
+
+ curlx_str_init(out);
+ if(*s != '\"')
+ return STRE_BEGQUOTE;
+ s++;
+ while(*s && (*s != '\"')) {
+ s++;
+ if(++len > max)
+ return STRE_BIG;
+ }
+ if(*s != '\"')
+ return STRE_ENDQUOTE;
+ out->str = (*linep) + 1;
+ out->len = len;
+ *linep = s + 1;
+ return STRE_OK;
+}
+
+/* Advance over a single character.
+ return non-zero on error */
+int curlx_str_single(const char **linep, char byte)
+{
+ DEBUGASSERT(linep && *linep);
+ if(**linep != byte)
+ return STRE_BYTE;
+ (*linep)++; /* move over it */
+ return STRE_OK;
+}
+
+/* Advance over a single space.
+ return non-zero on error */
+int curlx_str_singlespace(const char **linep)
+{
+ return curlx_str_single(linep, ' ');
+}
+
+/* given an ASCII character and max ascii, return TRUE if valid */
+#define valid_digit(x,m) \
+ (((x) >= '0') && ((x) <= m) && Curl_hexasciitable[(x)-'0'])
+
+/* We use 16 for the zero index (and the necessary bitwise AND in the loop)
+ to be able to have a non-zero value there to make valid_digit() able to
+ use the info */
+const unsigned char Curl_hexasciitable[] = {
+ 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* 0x30: 0 - 9 */
+ 0, 0, 0, 0, 0, 0, 0,
+ 10, 11, 12, 13, 14, 15, /* 0x41: A - F */
+ 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,
+ 10, 11, 12, 13, 14, 15 /* 0x61: a - f */
+};
+
+/* 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 */
+{
+ curl_off_t num = 0;
+ const char *p;
+ int m = (base == 10) ? '9' : /* the largest digit possible */
+ (base == 16) ? 'f' : '7';
+ DEBUGASSERT(linep && *linep && nump);
+ DEBUGASSERT((base == 8) || (base == 10) || (base == 16));
+ DEBUGASSERT(max >= 0); /* mostly to catch SIZE_T_MAX, which is too large */
+ *nump = 0;
+ p = *linep;
+ if(!valid_digit(*p, m))
+ return STRE_NO_NUM;
+ if(max < base) {
+ /* special-case low max scenario because check needs to be different */
+ do {
+ int n = Curl_hexval(*p++);
+ num = num * base + n;
+ if(num > max)
+ return STRE_OVERFLOW;
+ } while(valid_digit(*p, m));
+ }
+ else {
+ do {
+ int n = Curl_hexval(*p++);
+ if(num > ((max - n) / base))
+ return STRE_OVERFLOW;
+ num = num * base + n;
+ } while(valid_digit(*p, m));
+ }
+ *nump = num;
+ *linep = p;
+ return STRE_OK;
+}
+
+/* Get an unsigned decimal number with no leading space or minus. Leading
+ zeroes are accepted. return non-zero on error */
+int curlx_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 curlx_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 curlx_str_octal(const char **linep, curl_off_t *nump, curl_off_t max)
+{
+ return str_num_base(linep, nump, max, 8);
+}
+
+/*
+ * Parse a positive number up to 63-bit number written in ASCII. Skip leading
+ * blanks. No support for prefixes.
+ */
+int curlx_str_numblanks(const char **str, curl_off_t *num)
+{
+ curlx_str_passblanks(str);
+ return curlx_str_number(str, num, CURL_OFF_T_MAX);
+}
+
+/* CR or LF
+ return non-zero on error */
+int curlx_str_newline(const char **linep)
+{
+ DEBUGASSERT(linep && *linep);
+ if(ISNEWLINE(**linep)) {
+ (*linep)++;
+ return STRE_OK; /* yessir */
+ }
+ return STRE_NEWLINE;
+}
+
+#ifndef WITHOUT_LIBCURL
+/* case insensitive compare that the parsed string matches the given string.
+ Returns non-zero on match. */
+int curlx_str_casecompare(struct Curl_str *str, const char *check)
+{
+ size_t clen = check ? strlen(check) : 0;
+ return ((str->len == clen) && strncasecompare(str->str, check, clen));
+}
+#endif
+
+/* case sensitive string compare. Returns non-zero on match. */
+int curlx_str_cmp(struct Curl_str *str, const char *check)
+{
+ if(check) {
+ size_t clen = strlen(check);
+ return ((str->len == clen) && !strncmp(str->str, check, clen));
+ }
+ return !!(str->len);
+}
+
+/* Trim off 'num' number of bytes from the beginning (left side) of the
+ string. If 'num' is larger than the string, return error. */
+int curlx_str_nudge(struct Curl_str *str, size_t num)
+{
+ if(num <= str->len) {
+ str->str += num;
+ str->len -= num;
+ return STRE_OK;
+ }
+ return STRE_OVERFLOW;
+}
+
+/* Get the following character sequence that consists only of bytes not
+ present in the 'reject' string. Like strcspn(). */
+int curlx_str_cspn(const char **linep, struct Curl_str *out,
+ const char *reject)
+{
+ const char *s = *linep;
+ size_t len;
+ DEBUGASSERT(linep && *linep);
+
+ len = strcspn(s, reject);
+ if(len) {
+ out->str = s;
+ out->len = len;
+ *linep = &s[len];
+ return STRE_OK;
+ }
+ curlx_str_init(out);
+ return STRE_SHORT;
+}
+
+/* remove ISBLANK()s from both ends of the string */
+void curlx_str_trimblanks(struct Curl_str *out)
+{
+ while(out->len && ISBLANK(*out->str))
+ curlx_str_nudge(out, 1);
+
+ /* trim trailing spaces and tabs */
+ while(out->len && ISBLANK(out->str[out->len - 1]))
+ out->len--;
+}
+
+/* increase the pointer until it has moved over all blanks */
+void curlx_str_passblanks(const char **linep)
+{
+ while(ISBLANK(**linep))
+ (*linep)++; /* move over it */
+}