All of lore.kernel.org
 help / color / mirror / Atom feed
From: Cody P Schafer <dev@codyps.com>
To: ccan@lists.ozlabs.org
Cc: Cody P Schafer <dev@codyps.com>
Subject: [PATCH v4 1/4] mem: add mem helper functions
Date: Sat,  5 Sep 2015 21:21:03 -0400	[thread overview]
Message-ID: <1441502466-4754-2-git-send-email-dev@codyps.com> (raw)
In-Reply-To: <1441502466-4754-1-git-send-email-dev@codyps.com>

Signed-off-by: Cody P Schafer <dev@codyps.com>
---
 ccan/mem/mem.c      |  24 ++++++++
 ccan/mem/mem.h      | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 ccan/mem/test/api.c |  37 ++++++++++++-
 3 files changed, 217 insertions(+), 1 deletion(-)

diff --git a/ccan/mem/mem.c b/ccan/mem/mem.c
index 853f975..91c9961 100644
--- a/ccan/mem/mem.c
+++ b/ccan/mem/mem.c
@@ -40,3 +40,27 @@ void *memrchr(const void *s, int c, size_t n)
 	return NULL;
 }
 #endif
+
+void *mempbrkm(const void *data_, size_t len, const void *accept_, size_t accept_len)
+{
+	const char *data = data_, *accept = accept_;
+	size_t i, j;
+
+	for (i = 0; i < len; i++)
+		for (j = 0; j < accept_len; j++)
+			if (accept[j] == data[i])
+				return (void *)&data[i];
+	return NULL;
+}
+
+void *memcchr(void const *data, int c, size_t data_len)
+{
+	char const *p = data;
+	size_t i;
+
+	for (i = 0; i < data_len; i++)
+		if (p[i] != c)
+			return (void *)&p[i];
+
+	return NULL;
+}
diff --git a/ccan/mem/mem.h b/ccan/mem/mem.h
index dcb44b8..89b16d4 100644
--- a/ccan/mem/mem.h
+++ b/ccan/mem/mem.h
@@ -5,6 +5,7 @@
 #include "config.h"
 
 #include <string.h>
+#include <stdbool.h>
 
 #if !HAVE_MEMMEM
 void *memmem(const void *haystack, size_t haystacklen,
@@ -15,4 +16,160 @@ void *memmem(const void *haystack, size_t haystacklen,
 void *memrchr(const void *s, int c, size_t n);
 #endif
 
+/**
+ * mempbrkm - 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.
+ *
+ * Example:
+ *	char otherbytes[] = "Hello \0world";
+ *	size_t otherbytes_len = sizeof(otherbytes) - 1;
+ *	char *r = mempbrkm(otherbytes, otherbytes_len, "\0b", 2);
+ *	if (r) {
+ *		printf("Found %c\n", *r);
+ *	} else {
+ *		printf("Nada\n");
+ *	}
+ *
+ */
+void *mempbrkm(const void *data, size_t len, const void *accept, size_t accept_len);
+
+/**
+ * mempbrk - 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(otherbytes, otherbytes_len, "abcde");
+ *	if (r) {
+ *		printf("Found %c\n", *r);
+ *	} else {
+ *		printf("Nada\n");
+ *	}
+ */
+static inline char *mempbrk(const void *data, size_t len, const char *accept)
+{
+	return mempbrkm(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 complement of memchr().
+ *
+ * Returns a pointer to the first character which is _not_ @c. If all memory in
+ * @data is @c, returns NULL.
+ *
+ * Example:
+ *	char somebytes[] = "HI By\0e";
+ *	size_t bytes_len = sizeof(somebytes) - 1;
+ *	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);
+
+/**
+ * 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);
+}
+
+/**
+ * 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 memeq(data, prefix_len, prefix, prefix_len);
+}
+
+/**
+ * memeqstr - Is a byte array equal to a NUL terminated string?
+ * @data: byte array
+ * @length: length of @data in bytes
+ * @string: NUL terminated string
+ *
+ * The '\0' byte is ignored when checking if @bytes == @string.
+ *
+ * Example:
+ *	if (memeqstr(somebytes, bytes_len, "foo")) {
+ *		printf("somebytes == 'foo'!\n");
+ *	}
+ */
+static inline bool memeqstr(const void *data, size_t length, const char *string)
+{
+	return memeq(data, 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 void *a, size_t al, const char *s)
+{
+	return memstarts(a, al, s, strlen(s));
+}
+
+/**
+ * memends - Does this byte array end with a given byte-array suffix?
+ * @s: byte array
+ * @s_len: length in bytes
+ * @suffix: byte array suffix
+ * @suffix_len: length of suffix in bytes
+ *
+ * Returns true if @suffix appears as a substring at the end of @s,
+ * false otherwise.
+ */
+static inline bool memends(const void *s, size_t s_len, const void *suffix, size_t suffix_len)
+{
+	return (s_len >= suffix_len) && (memcmp((const char *)s + s_len - suffix_len,
+						suffix, suffix_len) == 0);
+}
+
 #endif /* CCAN_MEM_H */
diff --git a/ccan/mem/test/api.c b/ccan/mem/test/api.c
index 2ee15c5..89b6acb 100644
--- a/ccan/mem/test/api.c
+++ b/ccan/mem/test/api.c
@@ -8,9 +8,11 @@ int main(void)
 	char haystack2[] = "ab\0ab\0ab\0ab";
 	char needle1[] = "ab";
 	char needle2[] = "d\0e";
+	char scan1[] = "aaaab";
+	char scan2[] = "\0\0\0b";
 
 	/* This is how many tests you plan to run */
-	plan_tests(19);
+	plan_tests(42);
 
 	ok1(memmem(haystack1, sizeof(haystack1), needle1, 2) == haystack1);
 	ok1(memmem(haystack1, sizeof(haystack1), needle1, 3) == NULL);
@@ -37,6 +39,39 @@ int main(void)
 
 	ok1(memrchr(needle1, '\0', 2) == NULL);
 
+#define S(x) (x), sizeof(x) - 1
+	ok1(mempbrkm(S(haystack1), S("\0efgh")) == haystack1 + 4);
+	ok1(mempbrkm(S(haystack1), S("jklmn")) == NULL);
+	ok1(mempbrkm(S(haystack1), S("sd\0a")) == haystack1 + 0);
+
+	ok1(mempbrk(haystack1, sizeof(haystack1), "bcd\0a") == haystack1 + 1);
+	ok1(mempbrk(haystack1, sizeof(haystack1), "\0") == NULL);
+
+	ok1(memcchr(scan1, 'a', sizeof(scan1)) == scan1 + 4);
+	ok1(memcchr(scan1, 'b', sizeof(scan1)) == scan1);
+	ok1(memcchr(scan2, '\0', sizeof(scan2)) == scan2 + 3);
+	ok1(memcchr(scan2, '\0', sizeof(scan2) - 2) == NULL);
+
+	ok1(memeq(haystack1, sizeof(haystack1), haystack1, sizeof(haystack1)));
+	ok1(!memeq(haystack1, sizeof(haystack1), haystack2, sizeof(haystack2)));
+
+	ok1(memeqstr(scan1, sizeof(scan1) - 1, scan1));
+	ok1(!memeqstr(scan1, sizeof(scan1), scan1));
+	ok1(!memeqstr(scan1, sizeof(scan1), "aaaa"));
+
+	ok1(memstarts(S("a\0bcdef"), S("a\0bc")));
+	ok1(!memstarts(S("a\0bcdef"), S("a\0bcG")));
+	ok1(!memstarts(S("a\0bcdef"), S("a\0bcdefg")));
+
+	ok1(memstarts_str(scan1, sizeof(scan1), scan1));
+	ok1(!memstarts_str(scan1, sizeof(scan1), "ab"));
+
+	ok1(memends(S("abcdef"), S("abcdef")));
+	ok1(!memends(S("abcdef"), S("abcdefg")));
+	ok1(!memends(S("a\0bcdef"), S("a\0b")));
+	ok1(memends(S("a\0bcdef"), S("ef")));
+
+
 	/* This exits depending on whether all tests passed */
 	return exit_status();
 }
-- 
2.5.1

_______________________________________________
ccan mailing list
ccan@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/ccan

  reply	other threads:[~2015-09-06  1:21 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-06  1:21 [PATCH v4 0/4] mem: extend with a few additional helpers similar to existing string-only functions Cody P Schafer
2015-09-06  1:21 ` Cody P Schafer [this message]
2015-09-06  1:21 ` [PATCH v4 2/4] bytestring: use newly added mem helpers Cody P Schafer
2015-09-06  1:21 ` [PATCH v4 3/4] mem: mark all functions as PURE Cody P Schafer
2015-09-06  1:21 ` [PATCH v4 4/4] mem: add memends_str() helper for symmetry Cody P Schafer
2015-09-06 14:24 ` [PATCH v4 0/4] mem: extend with a few additional helpers similar to existing string-only functions David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1441502466-4754-2-git-send-email-dev@codyps.com \
    --to=dev@codyps.com \
    --cc=ccan@lists.ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.