[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