Browse Source

mem: Implement memrchr()

The memrchr() function, which works like memchr(), but searches from the
back of the region to the front is implemented in the GNU C library, but
isn't standard.

This patch adds an implementation of the function to the mem module, when
it's not available in the system C library.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
David Gibson 11 years ago
parent
commit
40b45c4cfb
4 changed files with 43 additions and 1 deletions
  1. 15 0
      ccan/mem/mem.c
  2. 4 0
      ccan/mem/mem.h
  3. 18 1
      ccan/mem/test/api.c
  4. 6 0
      tools/configurator/configurator.c

+ 15 - 0
ccan/mem/mem.c

@@ -25,3 +25,18 @@ void *memmem(const void *haystack, size_t haystacklen,
 	return NULL;
 	return NULL;
 }
 }
 #endif
 #endif
+
+#if !HAVE_MEMRCHR
+void *memrchr(const void *s, int c, size_t n)
+{
+	unsigned char *p = (unsigned char *)s;
+
+	while (n) {
+		if (p[n-1] == c)
+			return p + n - 1;
+		n--;
+	}
+
+	return NULL;
+}
+#endif

+ 4 - 0
ccan/mem/mem.h

@@ -11,4 +11,8 @@ void *memmem(const void *haystack, size_t haystacklen,
 	     const void *needle, size_t needlelen);
 	     const void *needle, size_t needlelen);
 #endif
 #endif
 
 
+#if !HAVE_MEMRCHR
+void *memrchr(const void *s, int c, size_t n);
+#endif
+
 #endif /* CCAN_MEM_H */
 #endif /* CCAN_MEM_H */

+ 18 - 1
ccan/mem/test/api.c

@@ -10,7 +10,7 @@ int main(void)
 	char needle2[] = "d\0e";
 	char needle2[] = "d\0e";
 
 
 	/* This is how many tests you plan to run */
 	/* This is how many tests you plan to run */
-	plan_tests(5);
+	plan_tests(19);
 
 
 	ok1(memmem(haystack1, sizeof(haystack1), needle1, 2) == haystack1);
 	ok1(memmem(haystack1, sizeof(haystack1), needle1, 2) == haystack1);
 	ok1(memmem(haystack1, sizeof(haystack1), needle1, 3) == NULL);
 	ok1(memmem(haystack1, sizeof(haystack1), needle1, 3) == NULL);
@@ -20,6 +20,23 @@ int main(void)
 	    == haystack2);
 	    == haystack2);
 	ok1(memmem(haystack2, sizeof(haystack2), needle2, 3) == NULL);
 	ok1(memmem(haystack2, sizeof(haystack2), needle2, 3) == NULL);
 
 
+	ok1(memrchr(haystack1, 'a', sizeof(haystack1)) == haystack1);
+	ok1(memrchr(haystack1, 'b', sizeof(haystack1)) == haystack1 + 1);
+	ok1(memrchr(haystack1, 'c', sizeof(haystack1)) == haystack1 + 2);
+	ok1(memrchr(haystack1, 'd', sizeof(haystack1)) == haystack1 + 3);
+	ok1(memrchr(haystack1, 'e', sizeof(haystack1)) == haystack1 + 5);
+	ok1(memrchr(haystack1, 'f', sizeof(haystack1)) == haystack1 + 6);
+	ok1(memrchr(haystack1, 'g', sizeof(haystack1)) == haystack1 + 7);
+	ok1(memrchr(haystack1, 'h', sizeof(haystack1)) == haystack1 + 8);
+	ok1(memrchr(haystack1, '\0', sizeof(haystack1)) == haystack1 + 9);
+	ok1(memrchr(haystack1, 'i', sizeof(haystack1)) == NULL);
+
+	ok1(memrchr(haystack2, 'a', sizeof(haystack2)) == haystack2 + 9);
+	ok1(memrchr(haystack2, 'b', sizeof(haystack2)) == haystack2 + 10);
+	ok1(memrchr(haystack2, '\0', sizeof(haystack2)) == haystack2 + 11);
+
+	ok1(memrchr(needle1, '\0', 2) == NULL);
+
 	/* This exits depending on whether all tests passed */
 	/* This exits depending on whether all tests passed */
 	return exit_status();
 	return exit_status();
 }
 }

+ 6 - 0
tools/configurator/configurator.c

@@ -214,6 +214,12 @@ static struct test tests[] = {
 	  "static void *func(void *h, size_t hl, void *n, size_t nl) {\n"
 	  "static void *func(void *h, size_t hl, void *n, size_t nl) {\n"
 	  "return memmem(h, hl, n, nl);"
 	  "return memmem(h, hl, n, nl);"
 	  "}\n", },
 	  "}\n", },
+	{ "HAVE_MEMRCHR", DEFINES_FUNC, NULL, NULL,
+	  "#define _GNU_SOURCE\n"
+	  "#include <string.h>\n"
+	  "static void *func(void *s, int c, size_t n) {\n"
+	  "return memrchr(s, c, n);"
+	  "}\n", },
 	{ "HAVE_MMAP", DEFINES_FUNC, NULL, NULL,
 	{ "HAVE_MMAP", DEFINES_FUNC, NULL, NULL,
 	  "#include <sys/mman.h>\n"
 	  "#include <sys/mman.h>\n"
 	  "static void *func(int fd) {\n"
 	  "static void *func(int fd) {\n"