Subject: [PATCH v2] compat: add memrchr()

From: Jonathan Nieder <[email-masked]>
Date: Fri, 15 Oct 2010 10:26:08 -0500

Reimplement another handy convenience function from glibc.  memrchr()
searches from the end of a memory area for a particular character.  It
is similar to strrchr() but takes a length argument and is
binary-safe.

The whole-directory rename detection patch could use this to find the
last '/' in a (possibly truncated) pathname.

The system memrchr() is used on glibc systems to provide a sanity
check that our code works with a non-custom implementation.  Yes, the
various BSDs have their own highly optimized memrchr(), too.  The
planned use of memrchr in git is for clarity, not speed, so it is not
obvious that the makefile+autoconf magic to use libc's implementation
on a wide variety of operating systems would be worth the time.

Signed-off-by: Jonathan Nieder <[email-masked]>
---
Ludvig Strigeus wrote:

> System memrchr uses a byte comparison rather than an int comparison.
> 
> "The memchr() function scans the first n bytes of the memory area pointed to by
> s for the character c. The first byte to match c (interpreted as an unsigned
> character) stops the operation. "

Oh, right.  (strchr() uses char, memchr() uses unsigned char.)

 git-compat-util.h |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/git-compat-util.h b/git-compat-util.h
index 2af8d3e..6de9dee 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -366,6 +366,9 @@ extern int git_vsnprintf(char *str, size_t maxsize,
 #define HAVE_STRCHRNUL
 #define HAVE_MEMPCPY
 #endif
+#if __GLIBC_PREREQ(2, 2)
+#define HAVE_MEMRCHR
+#endif
 #endif
 
 #ifndef HAVE_STRCHRNUL
@@ -386,6 +389,19 @@ static inline void *gitmempcpy(void *dest, const void *src, size_t n)
 }
 #endif
 
+#ifndef HAVE_MEMRCHR
+#define memrchr gitmemrchr
+static inline void *gitmemrchr(const void *s, int c, size_t n)
+{
+	const unsigned char *p = s;
+	p += n;
+	while (p != s)
+		if (*--p == (unsigned char) c)
+			return p;
+	return NULL;
+}
+#endif
+
 extern void release_pack_memory(size_t, int);
 
 typedef void (*try_to_free_t)(size_t);
-- 
1.7.2.3