[ccan] [PATCH] mem: module for common operations on addr+length regions
Cody P Schafer
dev at codyps.com
Wed Jul 30 15:47:03 EST 2014
Impliments 'mem' variants of <string.h> and <ccan/str/str.h> functions.
Signed-off-by: Cody P Schafer <dev at codyps.com>
---
Makefile-ccan | 1 +
ccan/mem/LICENSE | 1 +
ccan/mem/_info | 30 ++++++++
ccan/mem/mem.c | 53 ++++++++++++++
ccan/mem/mem.h | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++
ccan/mem/test/run.c | 69 ++++++++++++++++++
6 files changed, 350 insertions(+)
create mode 120000 ccan/mem/LICENSE
create mode 100644 ccan/mem/_info
create mode 100644 ccan/mem/mem.c
create mode 100644 ccan/mem/mem.h
create mode 100644 ccan/mem/test/run.c
diff --git a/Makefile-ccan b/Makefile-ccan
index 40d0389..e346119 100644
--- a/Makefile-ccan
+++ b/Makefile-ccan
@@ -69,6 +69,7 @@ MODS_WITH_SRC := antithread \
likely \
list \
md4 \
+ mem \
memmem \
net \
nfs \
diff --git a/ccan/mem/LICENSE b/ccan/mem/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/mem/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0
\ No newline at end of file
diff --git a/ccan/mem/_info b/ccan/mem/_info
new file mode 100644
index 0000000..a7d1139
--- /dev/null
+++ b/ccan/mem/_info
@@ -0,0 +1,30 @@
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * mem - provide various functions for handling memory (very similar to str for strings)
+ *
+ * This code provides (void *) + length replacements for functions
+ * that normally operate on NUL terminated strings.
+ *
+ * License: CC0
+ */
+int main(int argc, char *argv[])
+{
+ /* Expect exactly one argument */
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+ printf("ccan/memmem");
+ return 0;
+ }
+
+ if (strcmp(argv[1], "testdepends") == 0) {
+ printf("ccan/array_size");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/ccan/mem/mem.c b/ccan/mem/mem.c
new file mode 100644
index 0000000..ceb3d8f
--- /dev/null
+++ b/ccan/mem/mem.c
@@ -0,0 +1,53 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdbool.h>
+#include <ccan/mem/mem.h>
+
+size_t memspn(const char *data, size_t len, const char *accept, size_t accept_len)
+{
+ size_t i, j;
+ for (i = 0; i < len; i++) {
+ for (j = 0; j < accept_len; j++)
+ if (accept[j] == data[i])
+ goto cont_outer;
+ break;
+cont_outer:
+ ;
+ }
+ return i;
+}
+
+char *mempbrk(const char *data, size_t len, const char *accept, size_t accept_len)
+{
+ size_t i, j;
+ for (i = 0; i < len; i++)
+ for (j = 0; j < accept_len; j++)
+ if (accept[j] == data[i])
+ return (char *)&data[i];
+ return NULL;
+}
+
+size_t memcspn(const char *data, size_t len, const char *reject, size_t reject_len)
+{
+ size_t i, j;
+ for (i = 0; i < len; i++)
+ for (j = 0; j < reject_len; j++)
+ if (reject[j] == data[i])
+ return i;
+ return i;
+}
+
+void *memcchr(void const *data, int c, size_t data_len)
+{
+ char const *p = data;
+ while((size_t)(p - ((char const *)data)) < data_len) {
+ if (*p != c)
+ return (char *)p;
+ p++;
+ }
+
+ return NULL;
+}
diff --git a/ccan/mem/mem.h b/ccan/mem/mem.h
new file mode 100644
index 0000000..ccaeebe
--- /dev/null
+++ b/ccan/mem/mem.h
@@ -0,0 +1,196 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_MEM_H
+#define CCAN_MEM_H
+
+#include "config.h"
+
+#include <string.h>
+#include <stdbool.h>
+#include <ccan/memmem/memmem.h>
+
+/**
+ * mempbrk - locates the first occurrence in @data of any bytes in @accept
+ * @data: where we search
+ * @len: length of data in bytes
+ * @accept: array of bytes we search for
+ * @accept_len: # of bytes in accept
+ *
+ * Returns a pointer to the byte in @data that matches one of the bytes in
+ * @accept, or NULL if no such byte is found.
+ *
+ * Also see: strpbrk()
+ *
+ * Example:
+ * char somebytes[] = "Hell\0";
+ * char otherbytes[] = "Hello world";
+ * size_t bytes_len = sizeof(somebytes) - 1,
+ * otherbytes_len = sizeof(otherbytes) - 1;
+ * char *r;
+ *
+ * r = mempbrk(somebytes, bytes_len, otherbytes, otherbytes_len);
+ * if (r)
+ * printf("Found %c\n", *r);
+ * else
+ * printf("Nada\n");
+ */
+char *mempbrk(const char *data, size_t len, const char *accept, size_t accept_len);
+
+/**
+ * mempbrk_str - locates the first occurrence in @data of any bytes in @accept
+ * @data: where we search
+ * @len: length of data in bytes
+ * @accept: NUL terminated string containing the bytes we search for
+ *
+ * Returns a pointer to the byte in @data that matches one of the bytes in
+ * @accept, or NULL if no such byte is found.
+ *
+ * Example:
+ * r = mempbrk_str(somebytes, bytes_len, "world");
+ * if (r)
+ * printf("Found %c\n", *r);
+ * else
+ * printf("Nada\n");
+ */
+static inline char *mempbrk_str(const char *data, size_t len, const char *accept)
+{
+ return mempbrk(data, len, accept, strlen(accept));
+}
+
+/**
+ * memcchr - scan memory until a character does _not_ match @c
+ * @data: pointer to memory to scan
+ * @data_len: length of data
+ * @c: character to scan for
+ *
+ * The compliment of memchr().
+ *
+ * Returns a pointer to the first character which is _not_ @c. If all memory in
+ * @data is @c, returns NULL.
+ *
+ * Example:
+ * r = memcchr(somebytes, ' ', bytes_len);
+ * if (r)
+ * printf("Found %c after trimming spaces\n", *r);
+ */
+void *memcchr(void const *data, int c, size_t data_len);
+
+/**
+ * memstarts - determine if @data starts with @prefix
+ * @data: does this begin with @prefix?
+ * @data_len: bytes in @data
+ * @prefix: does @data begin with these bytes?
+ * @prefix_len: bytes in @prefix
+ *
+ * Returns true if @data starts with @prefix, otherwise return false.
+ *
+ * Example:
+ * if (memstarts(somebytes, bytes_len, otherbytes, otherbytes_len))
+ * printf("somebytes starts with otherbytes!\n");
+ */
+static inline bool memstarts(void const *data, size_t data_len,
+ void const *prefix, size_t prefix_len)
+{
+ if (prefix_len > data_len)
+ return false;
+ return !memcmp(data, prefix, prefix_len);
+}
+
+/**
+ * memeq - Are two byte arrays equal?
+ * @a: first array
+ * @al: bytes in first array
+ * @b: second array
+ * @bl: bytes in second array
+ *
+ * Example:
+ * if (memeq(somebytes, bytes_len, otherbytes, otherbytes_len))
+ * printf("memory blocks are the same!\n");
+ */
+static inline bool memeq(const void *a, size_t al, const void *b, size_t bl)
+{
+ return al == bl && !memcmp(a, b, bl);
+}
+
+/**
+ * memends - Does this memory end with this postfix?
+ * @m: bytes to test
+ * @m_len: length of @m
+ * @postfix: postfix to look for at end of @m
+ * @p_len: length of @postfix
+ *
+ * Example:
+ * if (memends(somebytes, bytes_len, otherbytes, otherbytes_len))
+ * printf("somebytes ends with otherbytes!\n");
+ */
+static inline bool memends(const char *m, size_t m_len, const char *postfix, size_t postfix_len)
+{
+ if (m_len < postfix_len)
+ return false;
+
+ return memeq(m + m_len - postfix_len, postfix_len, postfix, postfix_len);
+}
+
+/**
+ * memeq_str - Is a byte array equal to a NUL terminated string?
+ * @bytes: byte array
+ * @length: byte array length in bytes
+ * @string: NUL terminated string
+ *
+ * The '\0' byte is ignored when checking if @bytes == @string.
+ *
+ * Example:
+ * if (memeq_str(somebytes, bytes_len, "foo"))
+ * printf("somebytes == 'foo'!\n");
+ */
+static inline bool memeq_str(const char *bytes, size_t length, const char *string)
+{
+ return memeq(bytes, length, string, strlen(string));
+}
+
+/**
+ * memstarts_str - Does this byte array start with a string prefix?
+ * @a: byte array
+ * @al: length in bytes
+ * @s: string prefix
+ *
+ * Example:
+ * if (memstarts_str(somebytes, bytes_len, "It"))
+ * printf("somebytes starts with 'It'\n");
+ */
+static inline bool memstarts_str(const char *a, size_t al, const char *s)
+{
+ return memstarts(a, al, s, strlen(s));
+}
+
+/**
+ * memspn - return the length (in bytes) of the initial segment of @m which
+ * contains only bytes from @accept
+ */
+size_t memspn(const char *m, size_t m_len, const char *accept, size_t accept_len);
+
+/**
+ * memspn_str - like memspn, but uses a '\0' terminated string for it's @accept bytes
+ *
+ */
+static inline size_t memspn_str(const char *m, size_t m_len, const char *accept)
+{
+ return memspn(m, m_len, accept, strlen(accept));
+}
+
+/**
+ * memcspn - return the length (in bytes) of the initial segment of @m which
+ * contains none of the bytes from @reject
+ */
+size_t memcspn(const char *m, size_t m_len, const char *reject, size_t r_len);
+
+/**
+ * memcspn_str - like memcspn, but uses a '\0' terminated string for it's
+ * @reject bytes
+ *
+ */
+static inline size_t memcspn_str(const char *m, size_t m_len, const char *reject)
+{
+ return memcspn(m, m_len, reject, strlen(reject));
+}
+
+#endif /* CCAN_MEM_H */
diff --git a/ccan/mem/test/run.c b/ccan/mem/test/run.c
new file mode 100644
index 0000000..1fd27ed
--- /dev/null
+++ b/ccan/mem/test/run.c
@@ -0,0 +1,69 @@
+#include <ccan/array_size/array_size.h>
+#include <ccan/mem/mem.h>
+#include <ccan/tap/tap.h>
+
+#include <ccan/mem/mem.c>
+
+int main(void)
+{
+ /* 01 2345 */
+ char a[] = "hi\0bye";
+ char b[] = "by";
+ char c[] = "e\0";
+ char d[] = "hi";
+ char e[] = "hi\0";
+ char f[] = "e";
+
+#define A(x) x, sizeof(x)
+#define AM1(x) x, (sizeof(x) - 1)
+#define L(...) A((char []){ __VA_ARGS__ })
+#define S(...) AM1((char []){ __VA_ARGS__})
+
+ plan_tests(31);
+
+ ok1(mempbrk(A(a), L("by")) == &a[2]);
+ ok1(mempbrk(A(b), L("\0y")) == &b[1]);
+ ok1(mempbrk(A(b), L("FOO")) == (b + strlen(b)));
+ ok1(mempbrk(A(b), S("FOO")) == NULL);
+
+ ok1(mempbrk_str(A(a), "by") == &a[3]);
+ ok1(memchr(a, '\0', sizeof(a)) == &a[2]);
+ ok1(memchr(a, 'y', sizeof(a)) == &a[4]);
+
+ ok1(memstarts(a, sizeof(a), d, sizeof(d)));
+ ok1(!memstarts(d, sizeof(d), a, sizeof(a)));
+ ok1(!memstarts(a, sizeof(a), e, sizeof(e)));
+
+ ok1(!memeq(a, sizeof(a), d, sizeof(d)));
+ ok1(memeq(a, 3, d, sizeof(d)));
+
+ ok1(memends(a, sizeof(a), c, sizeof(c) - 1));
+ ok1(!memends(c, sizeof(c), a, sizeof(a)- 1));
+ ok1(!memends(a, sizeof(a), c, sizeof(c)));
+
+ ok1(!memeq_str(b, sizeof(b), "by"));
+ ok1(memeq_str(b, sizeof(b) - 1, "by"));
+
+ ok1(memstarts_str(a, sizeof(a), e));
+ ok1(memstarts_str(a, sizeof(a), "\0"));
+ ok1(memstarts_str(a, sizeof(a), "h"));
+
+ ok1(memspn(a, sizeof(a), b, sizeof(b)) == 0);
+ ok1(memspn(a, sizeof(a), d, sizeof(d)) == 3);
+
+ ok1(memspn_str(b, sizeof(b), "b") == 1);
+ ok1(memspn_str(b, sizeof(b), "a") == 0);
+
+ ok1(memcspn(a, sizeof(a), c, sizeof(c)) == 2);
+ ok1(memcspn(a, sizeof(a), f, sizeof(f) - 1) == 5);
+ ok1(memcspn(a, sizeof(a), "z", 1) == sizeof(a));
+
+
+ ok1(memcspn_str(a, sizeof(a), c) == 5);
+ ok1(memcspn_str(a, sizeof(a), "abcd") == 3);
+
+ ok1(memcchr(a, 'h', sizeof(a)) == &a[1]);
+ ok1(memcchr("z", 'z', 1) == NULL);
+
+ return exit_status();
+}
--
2.0.3
More information about the ccan
mailing list