Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b
Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/fmt/pl.c b/src/fmt/pl.c
new file mode 100644
index 0000000..a35fe77
--- /dev/null
+++ b/src/fmt/pl.c
@@ -0,0 +1,505 @@
+/**
+ * @file pl.c Pointer-length functions
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <ctype.h>
+#include <sys/types.h>
+#ifdef HAVE_STRINGS_H
+#define __EXTENSIONS__ 1
+#include <strings.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <re_types.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_fmt.h>
+
+
+/** Pointer-length NULL initialiser */
+const struct pl pl_null = {NULL, 0};
+
+
+/**
+ * Initialise a pointer-length object from a NULL-terminated string
+ *
+ * @param pl Pointer-length object to be initialised
+ * @param str NULL-terminated string
+ */
+void pl_set_str(struct pl *pl, const char *str)
+{
+ if (!pl || !str)
+ return;
+
+ pl->p = str;
+ pl->l = strlen(str);
+}
+
+
+/**
+ * Initialise a pointer-length object from current position and
+ * length of a memory buffer
+ *
+ * @param pl Pointer-length object to be initialised
+ * @param mb Memory buffer
+ */
+void pl_set_mbuf(struct pl *pl, const struct mbuf *mb)
+{
+ if (!pl || !mb)
+ return;
+
+ pl->p = (char *)mbuf_buf(mb);
+ pl->l = mbuf_get_left(mb);
+}
+
+
+/**
+ * Convert a pointer-length object to a numeric 32-bit value
+ *
+ * @param pl Pointer-length object
+ *
+ * @return 32-bit value
+ */
+uint32_t pl_u32(const struct pl *pl)
+{
+ uint32_t v=0, mul=1;
+ const char *p;
+
+ if (!pl || !pl->p)
+ return 0;
+
+ p = &pl->p[pl->l];
+ while (p > pl->p) {
+ const uint8_t c = *--p - '0';
+ if (c > 9)
+ return 0;
+ v += mul * c;
+ mul *= 10;
+ }
+
+ return v;
+}
+
+
+/**
+ * Convert a hex pointer-length object to a numeric 32-bit value
+ *
+ * @param pl Pointer-length object
+ *
+ * @return 32-bit value
+ */
+uint32_t pl_x32(const struct pl *pl)
+{
+ uint32_t v=0, mul=1;
+ const char *p;
+
+ if (!pl || !pl->p)
+ return 0;
+
+ p = &pl->p[pl->l];
+ while (p > pl->p) {
+
+ const char ch = *--p;
+ uint8_t c;
+
+ if ('0' <= ch && ch <= '9')
+ c = ch - '0';
+ else if ('A' <= ch && ch <= 'F')
+ c = ch - 'A' + 10;
+ else if ('a' <= ch && ch <= 'f')
+ c = ch - 'a' + 10;
+ else
+ return 0;
+
+ v += mul * c;
+ mul *= 16;
+ }
+
+ return v;
+}
+
+
+/**
+ * Convert a pointer-length object to a numeric 64-bit value
+ *
+ * @param pl Pointer-length object
+ *
+ * @return 64-bit value
+ */
+uint64_t pl_u64(const struct pl *pl)
+{
+ uint64_t v=0, mul=1;
+ const char *p;
+
+ if (!pl || !pl->p)
+ return 0;
+
+ p = &pl->p[pl->l];
+ while (p > pl->p) {
+ const uint8_t c = *--p - '0';
+ if (c > 9)
+ return 0;
+ v += mul * c;
+ mul *= 10;
+ }
+
+ return v;
+}
+
+
+/**
+ * Convert a hex pointer-length object to a numeric 64-bit value
+ *
+ * @param pl Pointer-length object
+ *
+ * @return 64-bit value
+ */
+uint64_t pl_x64(const struct pl *pl)
+{
+ uint64_t v=0, mul=1;
+ const char *p;
+
+ if (!pl || !pl->p)
+ return 0;
+
+ p = &pl->p[pl->l];
+ while (p > pl->p) {
+
+ const char ch = *--p;
+ uint8_t c;
+
+ if ('0' <= ch && ch <= '9')
+ c = ch - '0';
+ else if ('A' <= ch && ch <= 'F')
+ c = ch - 'A' + 10;
+ else if ('a' <= ch && ch <= 'f')
+ c = ch - 'a' + 10;
+ else
+ return 0;
+
+ v += mul * c;
+ mul *= 16;
+ }
+
+ return v;
+}
+
+
+/**
+ * Convert a pointer-length object to floating point representation.
+ * Both positive and negative numbers are supported, a string with a
+ * minus sign ('-') is treated as a negative number.
+ *
+ * @param pl Pointer-length object
+ *
+ * @return Double value
+ */
+double pl_float(const struct pl *pl)
+{
+ double v=0, mul=1;
+ const char *p;
+ bool neg = false;
+
+ if (!pl || !pl->p)
+ return 0;
+
+ p = &pl->p[pl->l];
+
+ while (p > pl->p) {
+
+ const char ch = *--p;
+
+ if ('0' <= ch && ch <= '9') {
+ v += mul * (ch - '0');
+ mul *= 10;
+ }
+ else if (ch == '.') {
+ v /= mul;
+ mul = 1;
+ }
+ else if (ch == '-' && p == pl->p) {
+ neg = true;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ return neg ? -v : v;
+}
+
+
+/**
+ * Check if pointer-length object is set
+ *
+ * @param pl Pointer-length object
+ *
+ * @return true if set, false if not set
+ */
+bool pl_isset(const struct pl *pl)
+{
+ return pl ? pl->p && pl->l : false;
+}
+
+
+/**
+ * Copy a pointer-length object to a NULL-terminated string
+ *
+ * @param pl Pointer-length object
+ * @param str Buffer for NULL-terminated string
+ * @param size Size of buffer
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int pl_strcpy(const struct pl *pl, char *str, size_t size)
+{
+ size_t len;
+
+ if (!pl || !pl->p || !str || !size)
+ return EINVAL;
+
+ len = min(pl->l, size-1);
+
+ memcpy(str, pl->p, len);
+ str[len] = '\0';
+
+ return 0;
+}
+
+
+/**
+ * Duplicate a pointer-length object to a NULL-terminated string
+ *
+ * @param dst Pointer to destination string (set on return)
+ * @param src Source pointer-length object
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int pl_strdup(char **dst, const struct pl *src)
+{
+ char *p;
+
+ if (!dst || !src || !src->p)
+ return EINVAL;
+
+ p = mem_alloc(src->l+1, NULL);
+ if (!p)
+ return ENOMEM;
+
+ memcpy(p, src->p, src->l);
+ p[src->l] = '\0';
+
+ *dst = p;
+
+ return 0;
+}
+
+
+/**
+ * Duplicate a pointer-length object to a new pointer-length object
+ *
+ * @param dst Destination pointer-length object (set on return)
+ * @param src Source pointer-length object
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int pl_dup(struct pl *dst, const struct pl *src)
+{
+ char *p;
+
+ if (!dst || !src || !src->p)
+ return EINVAL;
+
+ p = mem_alloc(src->l, NULL);
+ if (!p)
+ return ENOMEM;
+
+ memcpy(p, src->p, src->l);
+
+ dst->p = p;
+ dst->l = src->l;
+
+ return 0;
+}
+
+
+/**
+ * Compare a pointer-length object with a NULL-terminated string
+ * (case-sensitive)
+ *
+ * @param pl Pointer-length object
+ * @param str NULL-terminated string
+ *
+ * @return 0 if match, otherwise errorcode
+ */
+int pl_strcmp(const struct pl *pl, const char *str)
+{
+ struct pl s;
+
+ if (!pl || !str)
+ return EINVAL;
+
+ pl_set_str(&s, str);
+
+ return pl_cmp(pl, &s);
+}
+
+
+/**
+ * Compare a pointer-length object with a NULL-terminated string
+ * (case-insensitive)
+ *
+ * @param pl Pointer-length object
+ * @param str NULL-terminated string
+ *
+ * @return 0 if match, otherwise errorcode
+ */
+int pl_strcasecmp(const struct pl *pl, const char *str)
+{
+ struct pl s;
+
+ if (!pl || !str)
+ return EINVAL;
+
+ pl_set_str(&s, str);
+
+ return pl_casecmp(pl, &s);
+}
+
+
+/**
+ * Compare two pointer-length objects (case-sensitive)
+ *
+ * @param pl1 First pointer-length object
+ * @param pl2 Second pointer-length object
+ *
+ * @return 0 if match, otherwise errorcode
+ */
+int pl_cmp(const struct pl *pl1, const struct pl *pl2)
+{
+ if (!pl1 || !pl2)
+ return EINVAL;
+
+ /* Different length -> no match */
+ if (pl1->l != pl2->l)
+ return EINVAL;
+
+ /* Zero-length strings are always identical */
+ if (pl1->l == 0)
+ return 0;
+
+ /*
+ * ~35% speed increase for fmt/pl test
+ */
+
+ /* The two pl's are the same */
+ if (pl1 == pl2)
+ return 0;
+
+ /* Two different pl's pointing to same string */
+ if (pl1->p == pl2->p)
+ return 0;
+
+ return 0 == memcmp(pl1->p, pl2->p, pl1->l) ? 0 : EINVAL;
+}
+
+
+#ifndef HAVE_STRINGS_H
+static int casecmp(const struct pl *pl, const char *str)
+{
+ size_t i = 0;
+
+#define LOWER(d) ((d) | 0x20202020)
+ const uint32_t *p1 = (uint32_t *)pl->p;
+ const uint32_t *p2 = (uint32_t *)str;
+ const size_t len = pl->l & ~0x3;
+
+ /* Skip any unaligned pointers */
+ if (((size_t)pl->p) & (sizeof(void *) - 1))
+ goto next;
+ if (((size_t)str) & (sizeof(void *) - 1))
+ goto next;
+
+ /* Compare word-wise */
+ for (; i<len; i+=4) {
+ if (LOWER(*p1++) != LOWER(*p2++))
+ return EINVAL;
+ }
+
+ next:
+ /* Compare byte-wise */
+ for (; i<pl->l; i++) {
+ if (tolower(pl->p[i]) != tolower(str[i]))
+ return EINVAL;
+ }
+
+ return 0;
+}
+#endif
+
+
+/**
+ * Compare two pointer-length objects (case-insensitive)
+ *
+ * @param pl1 First pointer-length object
+ * @param pl2 Second pointer-length object
+ *
+ * @return 0 if match, otherwise errorcode
+ */
+int pl_casecmp(const struct pl *pl1, const struct pl *pl2)
+{
+ if (!pl1 || !pl2)
+ return EINVAL;
+
+ /* Different length -> no match */
+ if (pl1->l != pl2->l)
+ return EINVAL;
+
+ /* Zero-length strings are always identical */
+ if (pl1->l == 0)
+ return 0;
+
+ /*
+ * ~35% speed increase for fmt/pl test
+ */
+
+ /* The two pl's are the same */
+ if (pl1 == pl2)
+ return 0;
+
+ /* Two different pl's pointing to same string */
+ if (pl1->p == pl2->p)
+ return 0;
+
+#ifdef HAVE_STRINGS_H
+ return 0 == strncasecmp(pl1->p, pl2->p, pl1->l) ? 0 : EINVAL;
+#else
+ return casecmp(pl1, pl2->p);
+#endif
+}
+
+
+/**
+ * Locate character in pointer-length string
+ *
+ * @param pl Pointer-length string
+ * @param c Character to locate
+ *
+ * @return Pointer to first char if found, otherwise NULL
+ */
+const char *pl_strchr(const struct pl *pl, char c)
+{
+ const char *p, *end;
+
+ if (!pl)
+ return NULL;
+
+ end = pl->p + pl->l;
+ for (p = pl->p; p < end; p++) {
+ if (*p == c)
+ return p;
+ }
+
+ return NULL;
+}