Skip to contentSkip to conversation

Add strchrnul()

PATCH In review René Scharfe 8 participants 18 messages Jun 15, 2016 Kbuild

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 Add strchrnul()

As suggested by Pierre Habouzit, add strchrnul(). It's a useful GNU extension and can simplify string parser code. There are several places in git that can be converted to strchrnul(); as a trivial example, this patch introduces its usage to builtin-fetch--tool.c.

---

 Makefile              |   13 +++++++++++++
 builtin-fetch--tool.c |    8 ++------
 compat/strchrnul.c    |    8 ++++++++
 git-compat-util.h     |    5 +++++
 4 files changed, 28 insertions(+), 6 deletions(-)
Makefile +13 -0
index 0d5590f..578c999 100644
@@ -30,6 +30,8 @@ all::
 #
 # Define NO_MEMMEM if you don't have memmem.
 #
+# Define NO_STRCHRNUL if you don't have strchrnul.
+#
 # Define NO_STRLCPY if you don't have strlcpy.
 #
 # Define NO_STRTOUMAX if you don't have strtoumax in the C library.
@@ -406,6 +408,7 @@ ifeq ($(uname_S),Darwin)
 	OLD_ICONV = UnfortunatelyYes
 	NO_STRLCPY = YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 endif
 ifeq ($(uname_S),SunOS)
 	NEEDS_SOCKET = YesPlease
@@ -413,6 +416,7 @@ ifeq ($(uname_S),SunOS)
 	SHELL_PATH = /bin/bash
 	NO_STRCASESTR = YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	NO_HSTRERROR = YesPlease
 	ifeq ($(uname_R),5.8)
 		NEEDS_LIBICONV = YesPlease
@@ -438,6 +442,7 @@ ifeq ($(uname_O),Cygwin)
 	NO_D_INO_IN_DIRENT = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	NO_SYMLINK_HEAD = YesPlease
 	NEEDS_LIBICONV = YesPlease
 	NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
@@ -452,12 +457,14 @@ endif
 ifeq ($(uname_S),FreeBSD)
 	NEEDS_LIBICONV = YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	BASIC_CFLAGS += -I/usr/local/include
 	BASIC_LDFLAGS += -L/usr/local/lib
 endif
 ifeq ($(uname_S),OpenBSD)
 	NO_STRCASESTR = YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	NEEDS_LIBICONV = YesPlease
 	BASIC_CFLAGS += -I/usr/local/include
 	BASIC_LDFLAGS += -L/usr/local/lib
@@ -473,6 +480,7 @@ endif
 ifeq ($(uname_S),AIX)
 	NO_STRCASESTR=YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	NO_STRLCPY = YesPlease
 	NEEDS_LIBICONV=YesPlease
 endif
@@ -485,6 +493,7 @@ ifeq ($(uname_S),IRIX64)
 	NO_SETENV=YesPlease
 	NO_STRCASESTR=YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_SOCKADDR_STORAGE=YesPlease
 	SHELL_PATH=/usr/gnu/bin/bash
@@ -695,6 +704,10 @@ ifdef NO_MEMMEM
 	COMPAT_CFLAGS += -DNO_MEMMEM
 	COMPAT_OBJS += compat/memmem.o
 endif
+ifdef NO_STRCHRNUL
+	COMPAT_CFLAGS += -DNO_STRCHRNUL
+	COMPAT_OBJS += compat/strchrnul.o
+endif
 
 ifdef THREADED_DELTA_SEARCH
 	BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH
builtin-fetch--tool.c +2 -6
index 6a78517..ed60847 100644
@@ -435,9 +435,7 @@ static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu
 				cp++;
 			if (!*cp)
 				break;
-			np = strchr(cp, '\n');
-			if (!np)
-				np = cp + strlen(cp);
+			np = strchrnul(cp, '\n');
 			if (pass) {
 				lrr_list[i].line = cp;
 				lrr_list[i].name = cp + 41;
@@ -461,9 +459,7 @@ static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu
 			rref++;
 		if (!*rref)
 			break;
-		next = strchr(rref, '\n');
-		if (!next)
-			next = rref + strlen(rref);
+		next = strchrnul(rref, '\n');
 		rreflen = next - rref;
 
 		for (i = 0; i < lrr_count; i++) {
compat/strchrnul.c new file +8 -0
new file mode 100644
index 0000000..51839fe
@@ -0,0 +1,8 @@
+#include "../git-compat-util.h"
+
+char *gitstrchrnul(const char *s, int c)
+{
+	while (*s && *s != c)
+		s++;
+	return (char *)s;
+}
git-compat-util.h +5 -0
index 7b29d1b..e72654b 100644
@@ -183,6 +183,11 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
                 const void *needle, size_t needlelen);
 #endif
 
+#ifdef NO_STRCHRNUL
+#define strchrnul gitstrchrnul
+char *gitstrchrnul(const char *s, int c);
+#endif
+
 extern void release_pack_memory(size_t, int);
 
 static inline char* xstrdup(const char *str)
#1 lore raw
Quoted 4 lines · René Scharfe

As suggested by Pierre Habouzit, add strchrnul(). It's a useful GNU extension and can simplify string parser code. There are several places in git that can be converted to strchrnul(); as a trivial example, this patch introduces its usage to builtin-fetch--tool.c.

Minor nit: a comment (in the code or even in the commit message) describing the what the function does would be nice. On a GNU system, one can look at the man page, but on others there is no indication of what it does except for reading the code (and maybe the answer is "this is a common library function, you idiot", but I am familiar with many GNU extensions and didn't know this one).

-Peff

#2 lore raw
In reply to René Scharfe
Quoted 19 lines · René Scharfe

As suggested by Pierre Habouzit, add strchrnul(). It's a useful GNU extension and can simplify string parser code. There are several places in git that can be converted to strchrnul(); as a trivial example, this patch introduces its usage to builtin-fetch--tool.c.

---

 Makefile              |   13 +++++++++++++
 builtin-fetch--tool.c |    8 ++------
 compat/strchrnul.c    |    8 ++++++++
 git-compat-util.h     |    5 +++++
 4 files changed, 28 insertions(+), 6 deletions(-)
Makefile +0 -0
index 0d5590f..578c999 100644

Makefile all:: · line 34

Quoted 5 lines
Makefile +2 -0
@@ -30,6 +30,8 @@ all::
 #
 # Define NO_MEMMEM if you don't have memmem.
 #
+# Define NO_STRCHRNUL if you don't have strchrnul.
+#

This seems overly complicated. How about this instead?

From: Andreas Ericsson <[email protected]>
Subject: [PATCH] Add strchrnul()

As suggested by Pierre Habouzit, add strchrnul(). It's a useful GNU extension and can simplify string parser code. There are several places in git that can be converted to strchrnul(); as a trivial example, this patch introduces its usage to builtin-fetch--tool.c.

strchrnul() was introduced in glibc in April 1999 and included in glibc-2.1. Checking for that version means the majority of all git users would get to use the optimized version in glibc. Of the remaining few some might get to use a slightly slower version than necessary but probably not slower than what we have today.

Original patch by Rene Scharfe <[email protected]>

---

I'm fairly much against forcing people to know what library functions they have in order to get software to compile properly. This is, imo, a neater solution, and also inlines the function as suggested by Dscho.

git-compat-util.h +0 -0
index 7b29d1b..9fedf33 100644
@@ -105,6 +105,18 @@ extern void set_die_routine(void (*routine)(const char *err

extern void set_error_routine(void (*routine)(const char *err, va_list params)) extern void set_warn_routine(void (*routine)(const char *warn, va_list params))

+
+#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1) +# define strchrnul(s, c) gitstrchrnul(s, c) +static inline char *gitstrchrnul(const char *s, int c) +{
+ while (*s && *s != c)
+ s++;
+
+ return (char *)s;
+}
+#endif
+
#ifdef NO_MMAP

#ifndef PROT_READ

builtin-fetch--tool.c +0 -0
index 6a78517..ed60847 100644
@@ -435,9 +435,7 @@ static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu
				cp++;
			if (!*cp)
				break;
-			np = strchr(cp, '\n');
-			if (!np)
-				np = cp + strlen(cp);
+			np = strchrnul(cp, '\n');
			if (pass) {
				lrr_list[i].line = cp;
				lrr_list[i].name = cp + 41;
@@ -461,9 +459,7 @@ static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu
			rref++;
		if (!*rref)
			break;
-		next = strchr(rref, '\n');
-		if (!next)
-			next = rref + strlen(rref);
+		next = strchrnul(rref, '\n');
		rreflen = next - rref;

		for (i = 0; i < lrr_count; i++) {
Signature · 3 lines
Andreas Ericsson                   [email protected]
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231
#3 lore raw

PATCH 1/1 Simplify strchrnul() compat code

From: Andreas Ericsson <[email protected]>

strchrnul() was introduced in glibc in April 1999 and included in glibc-2.1. Checking for that version means the majority of all git users would get to use the optimized version in glibc. Of the remaining few some might get to use a slightly slower version than necessary but probably not slower than what we have today.

Rediffed-against-next-by Rene Scharfe <[email protected]>

---
I agree that we can do without providing a way to use a native version outside glibc until we actually encounter such a thing.

 Makefile           |   13 -------------
 compat/strchrnul.c |    8 --------
 git-compat-util.h  |    9 +++++++--
 3 files changed, 7 insertions(+), 23 deletions(-)
Makefile +0 -13
index 4f1d7ca..4a5d2b9 100644
@@ -30,8 +30,6 @@ all::
 #
 # Define NO_MEMMEM if you don't have memmem.
 #
-# Define NO_STRCHRNUL if you don't have strchrnul.
-#
 # Define NO_STRLCPY if you don't have strlcpy.
 #
 # Define NO_STRTOUMAX if you don't have strtoumax in the C library.
@@ -409,7 +407,6 @@ ifeq ($(uname_S),Darwin)
 	OLD_ICONV = UnfortunatelyYes
 	NO_STRLCPY = YesPlease
 	NO_MEMMEM = YesPlease
-	NO_STRCHRNUL = YesPlease
 endif
 ifeq ($(uname_S),SunOS)
 	NEEDS_SOCKET = YesPlease
@@ -417,7 +414,6 @@ ifeq ($(uname_S),SunOS)
 	SHELL_PATH = /bin/bash
 	NO_STRCASESTR = YesPlease
 	NO_MEMMEM = YesPlease
-	NO_STRCHRNUL = YesPlease
 	NO_HSTRERROR = YesPlease
 	ifeq ($(uname_R),5.8)
 		NEEDS_LIBICONV = YesPlease
@@ -443,7 +439,6 @@ ifeq ($(uname_O),Cygwin)
 	NO_D_INO_IN_DIRENT = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_MEMMEM = YesPlease
-	NO_STRCHRNUL = YesPlease
 	NO_SYMLINK_HEAD = YesPlease
 	NEEDS_LIBICONV = YesPlease
 	NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
@@ -458,14 +453,12 @@ endif
 ifeq ($(uname_S),FreeBSD)
 	NEEDS_LIBICONV = YesPlease
 	NO_MEMMEM = YesPlease
-	NO_STRCHRNUL = YesPlease
 	BASIC_CFLAGS += -I/usr/local/include
 	BASIC_LDFLAGS += -L/usr/local/lib
 endif
 ifeq ($(uname_S),OpenBSD)
 	NO_STRCASESTR = YesPlease
 	NO_MEMMEM = YesPlease
-	NO_STRCHRNUL = YesPlease
 	NEEDS_LIBICONV = YesPlease
 	BASIC_CFLAGS += -I/usr/local/include
 	BASIC_LDFLAGS += -L/usr/local/lib
@@ -481,7 +474,6 @@ endif
 ifeq ($(uname_S),AIX)
 	NO_STRCASESTR=YesPlease
 	NO_MEMMEM = YesPlease
-	NO_STRCHRNUL = YesPlease
 	NO_STRLCPY = YesPlease
 	NEEDS_LIBICONV=YesPlease
 endif
@@ -494,7 +486,6 @@ ifeq ($(uname_S),IRIX64)
 	NO_SETENV=YesPlease
 	NO_STRCASESTR=YesPlease
 	NO_MEMMEM = YesPlease
-	NO_STRCHRNUL = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_SOCKADDR_STORAGE=YesPlease
 	SHELL_PATH=/usr/gnu/bin/bash
@@ -705,10 +696,6 @@ ifdef NO_MEMMEM
 	COMPAT_CFLAGS += -DNO_MEMMEM
 	COMPAT_OBJS += compat/memmem.o
 endif
-ifdef NO_STRCHRNUL
-	COMPAT_CFLAGS += -DNO_STRCHRNUL
-	COMPAT_OBJS += compat/strchrnul.o
-endif
 
 ifdef THREADED_DELTA_SEARCH
 	BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH
compat/strchrnul.c deleted +0 -8
deleted file mode 100644
index 51839fe..0000000
@@ -1,8 +0,0 @@
-#include "../git-compat-util.h"
-
-char *gitstrchrnul(const char *s, int c)
-{
-	while (*s && *s != c)
-		s++;
-	return (char *)s;
-}
git-compat-util.h +7 -2
index e72654b..11e6df6 100644
@@ -183,9 +183,14 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
                 const void *needle, size_t needlelen);
 #endif
 
-#ifdef NO_STRCHRNUL
+#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)
 #define strchrnul gitstrchrnul
-char *gitstrchrnul(const char *s, int c);
+static inline char *gitstrchrnul(const char *s, int c)
+{
+        while (*s && *s != c)
+                s++;
+        return (char *)s;
+}
 #endif
 
 extern void release_pack_memory(size_t, int);
#4 lore raw

Re: [PATCH] Simplify strchrnul() compat code

git-compat-util.h void *gitmemmem(const void *haystack, size_t haystacklen, · line 186

Quoted 3 lines · René Scharfe
git-compat-util.h +1 -1
-#ifdef NO_STRCHRNUL
+#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)

This will break things for users of glibc-2.1.1 (the first release still available from ftp://sources.redhat.com/pub/glibc/old-releases that includes the strchrnul() function), since __GLIBC_PREREQ() was invented after strchrnul() was introduced.

Replacing __GLIBC__ with __GLIBC_PREREQ (as in the original patch) will solve it nicely. Users of glibc-2.1.1 will be the odd minority where strchrnul() is available in their libc but not used.

Signature · 3 lines
Andreas Ericsson                   [email protected]
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231
#5 lore raw

Re: [PATCH] Simplify strchrnul() compat code

Quoted 4 lines · Andreas Ericsson
Quoted 2 lines · René Scharfe

-#ifdef NO_STRCHRNUL
+#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)

Quoted 8 lines

This will break things for users of glibc-2.1.1 (the first release still available from ftp://sources.redhat.com/pub/glibc/old-releases that includes the strchrnul() function), since __GLIBC_PREREQ() was invented after strchrnul() was introduced.

Replacing __GLIBC__ with __GLIBC_PREREQ (as in the original patch) will solve it nicely. Users of glibc-2.1.1 will be the odd minority where strchrnul() is available in their libc but not used.

Do you mean this on top of René's patch? Although I do not think I saw "the original patch" that did it this way, I think it makes sense.

git-compat-util.h +1 -1
index 11e6df6..dd96f7a 100644
@@ -183,7 +183,7 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
                 const void *needle, size_t needlelen);
 #endif
 
-#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)
+#if !defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 1)
 #define strchrnul gitstrchrnul
 static inline char *gitstrchrnul(const char *s, int c)
 {
#6 lore raw

Re: [PATCH] Simplify strchrnul() compat code

Quoted 10 lines · Junio C Hamano
Quoted 8 lines · Andreas Ericsson
Quoted 2 lines · René Scharfe

-#ifdef NO_STRCHRNUL
+#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)

This will break things for users of glibc-2.1.1 (the first release still available from ftp://sources.redhat.com/pub/glibc/old-releases that includes the strchrnul() function), since __GLIBC_PREREQ() was invented after strchrnul() was introduced.

Quoted 5 lines
Quoted 3 lines

Replacing __GLIBC__ with __GLIBC_PREREQ (as in the original patch) will solve it nicely. Users of glibc-2.1.1 will be the odd minority where strchrnul() is available in their libc but not used.

Do you mean this on top of René's patch?

Yes.

Quoted 2 lines

Although I do not
think I saw "the original patch" that did it this way,

My memory seems to be failing. I never committed my proposal to my repo, and the one I sent out was the __GLIBC__ || !__GLIBC_PREREQ thing. My apologies.

Signature · 3 lines
Andreas Ericsson                   [email protected]
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231
#7 lore raw

Re: [PATCH] Simplify strchrnul() compat code

In reply to Junio C Hamano
Quoted 24 lines · Junio C Hamano
Quoted 4 lines · Andreas Ericsson
Quoted 2 lines · René Scharfe

-#ifdef NO_STRCHRNUL
+#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)

Quoted 8 lines

This will break things for users of glibc-2.1.1 (the first release still available from ftp://sources.redhat.com/pub/glibc/old-releases that includes the strchrnul() function), since __GLIBC_PREREQ() was invented after strchrnul() was introduced.

Replacing __GLIBC__ with __GLIBC_PREREQ (as in the original patch) will solve it nicely. Users of glibc-2.1.1 will be the odd minority where strchrnul() is available in their libc but not used.

Do you mean this on top of René's patch? Although I do not think I saw "the original patch" that did it this way, I think it makes sense.

git-compat-util.h +0 -0
index 11e6df6..dd96f7a 100644

git-compat-util.h void *gitmemmem(const void *haystack, size_t haystacklen, · line 189

Quoted 8 lines
git-compat-util.h +1 -1
@@ -183,7 +183,7 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
                 const void *needle, size_t needlelen);
 #endif
 
-#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)
+#if !defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 1)
 #define strchrnul gitstrchrnul
 static inline char *gitstrchrnul(const char *s, int c)
 {

I just tested it on my machine (OS X Tiger) now that it's in 'next', and this breaks the build:

CC git.o
In file included from builtin.h:4,

                 from git.c:1:

git-compat-util.h:187:48: error: missing binary operator before token "("
make: *** [git.o] Error 1

I don't think I have __GLIBC_PREREQ defined anywhere I can find.

Dave.

#8 lore raw

Re: [PATCH] Simplify strchrnul() compat code

Quoted 14 lines · David Symonds

git-compat-util.h void *gitmemmem(const void *haystack, size_t haystacklen, · line 189

Quoted 9 lines · Junio C Hamano
git-compat-util.h +1 -1
@@ -183,7 +183,7 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
                 const void *needle, size_t needlelen);
 #endif
 
-#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)
+#if !defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 1)
 #define strchrnul gitstrchrnul
 static inline char *gitstrchrnul(const char *s, int c)
 {

I just tested it on my machine (OS X Tiger) now that it's in 'next', and this breaks the build:

Quoted 8 lines

CC git.o
In file included from builtin.h:4,

                 from git.c:1:

git-compat-util.h:187:48: error: missing binary operator before token "("
make: *** [git.o] Error 1

I don't think I have __GLIBC_PREREQ defined anywhere I can find.

Turn the && in that line into || and it should work.

-- Hannes

#9 lore raw

Re: [PATCH] Simplify strchrnul() compat code

Quoted 22 lines · Johannes Sixt
Quoted 21 lines · David Symonds

git-compat-util.h void *gitmemmem(const void *haystack, size_t haystacklen, · line 189

Quoted 9 lines · Junio C Hamano
git-compat-util.h +1 -1
@@ -183,7 +183,7 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
                 const void *needle, size_t needlelen);
 #endif
 
-#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)
+#if !defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 1)
 #define strchrnul gitstrchrnul
 static inline char *gitstrchrnul(const char *s, int c)
 {

I just tested it on my machine (OS X Tiger) now that it's in 'next', and this breaks the build:

CC git.o
In file included from builtin.h:4,

                 from git.c:1:

git-compat-util.h:187:48: error: missing binary operator before token "("
make: *** [git.o] Error 1

Quoted 3 lines
Quoted 1 line

I don't think I have __GLIBC_PREREQ defined anywhere I can find.

Turn the && in that line into || and it should work.

Nope, no dice. Plus, that'd change the logic. I also tried turning the (!X && !Y) into (X || Y) to no avail.

Dave.

#10 lore raw

Re: [PATCH] Simplify strchrnul() compat code

Quoted 7 lines · David Symonds
Quoted 3 lines · Johannes Sixt
Quoted 1 line · David Symonds

I don't think I have __GLIBC_PREREQ defined anywhere I can find.

Turn the && in that line into || and it should work.

Nope, no dice. Plus, that'd change the logic. I also tried turning the (!X && !Y) into (X || Y) to no avail.

Ok, then how about this?

---

git-compat-util.h +7 -1
index 3d147b6..276a437 100644
@@ -184,7 +184,13 @@ void *gitmemmem(const void *haystack,
                 const void *needle, size_t needlelen);
 #endif
 
-#if !defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 1)
+#ifdef __GLIBC_PREREQ
+#if __GLIBC_PREREQ(2, 1)
+#define HAVE_STRCHRNUL
+#endif
+#endif
+
+#ifndef HAVE_STRCHRNUL
 #define strchrnul gitstrchrnul
 static inline char *gitstrchrnul(const char *s, int c)
 {
#11 lore raw

Re: [PATCH] Simplify strchrnul() compat code

Quoted 31 lines · Johannes Sixt
Quoted 7 lines · David Symonds
Quoted 3 lines · Johannes Sixt
Quoted 1 line · David Symonds

I don't think I have __GLIBC_PREREQ defined anywhere I can find.

Turn the && in that line into || and it should work.

Nope, no dice. Plus, that'd change the logic. I also tried turning the (!X && !Y) into (X || Y) to no avail.

Ok, then how about this?

---

git-compat-util.h +7 -1
index 3d147b6..276a437 100644
@@ -184,7 +184,13 @@ void *gitmemmem(const void *haystack,
                  const void *needle, size_t needlelen);
  #endif
 
-#if !defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 1)
+#ifdef __GLIBC_PREREQ
+#if __GLIBC_PREREQ(2, 1)
+#define HAVE_STRCHRNUL
+#endif
+#endif
+
+#ifndef HAVE_STRCHRNUL
 
  #define strchrnul gitstrchrnul
  static inline char *gitstrchrnul(const char *s, int c)
Quoted 1 line
  {

Yep, that works just fine. Ack.

Dave.

#12 lore raw

PATCH 1/1 Fix preprocessor logic that determines the availablity of strchrnul().

Apart from the error in the condition (&& should actually be ||), the construct

   #if !defined(A) || !A

leads to a syntax error in the C preprocessor if A is indeed not defined.

---
 git-compat-util.h |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)
git-compat-util.h +7 -1
index 3d147b6..276a437 100644
@@ -184,7 +184,13 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
                 const void *needle, size_t needlelen);
 #endif
 
-#if !defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 1)
+#ifdef __GLIBC_PREREQ
+#if __GLIBC_PREREQ(2, 1)
+#define HAVE_STRCHRNUL
+#endif
+#endif
+
+#ifndef HAVE_STRCHRNUL
 #define strchrnul gitstrchrnul
 static inline char *gitstrchrnul(const char *s, int c)
 {
Signature · 1 line
1.5.3.5.578.g1f8ec
#13 lore raw

Re: [PATCH] Simplify strchrnul() compat code

In reply to David Symonds
Quoted 11 lines · David Symonds
Quoted 9 lines · Johannes Sixt
git-compat-util.h +7 -1
-#if !defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 1)
+#ifdef __GLIBC_PREREQ
+#if __GLIBC_PREREQ(2, 1)
+#define HAVE_STRCHRNUL
+#endif
+#endif
+
+#ifndef HAVE_STRCHRNUL
Quoted 5 lines
Quoted 3 lines
  #define strchrnul gitstrchrnul
  static inline char *gitstrchrnul(const char *s, int c)
  {

Yep, that works just fine. Ack.

This version has also the following advantage that you can set HAVE_STRCHRNULL if above test does not detect it in your library.

Althought you'd better write then:

+#if __GLIBC_PREREQ(2, 1) && !defined(HAVE_STRCHRNUL)

Ack.

Signature · 3 lines
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
#14 lore raw
In reply to Andreas Ericsson

[Cc: Andreas Ericsson <[email protected]>,
René Scharfe <[email protected]>,
Junio C Hamano <[email protected]>,
[email protected]]

Quoted 15 lines · Andreas Ericsson
Quoted 14 lines · René Scharfe

As suggested by Pierre Habouzit, add strchrnul(). It's a useful GNU extension and can simplify string parser code. There are several places in git that can be converted to strchrnul(); as a trivial example, this patch introduces its usage to builtin-fetch--tool.c.

---

 Makefile              |   13 +++++++++++++
 builtin-fetch--tool.c |    8 ++------
 compat/strchrnul.c    |    8 ++++++++
 git-compat-util.h     |    5 +++++
 4 files changed, 28 insertions(+), 6 deletions(-)
Quoted 10 lines

Makefile all:: · line 34

Quoted 10 lines
Makefile +2 -0
index 0d5590f..578c999 100644
@@ -30,6 +30,8 @@ all::
 #
 # Define NO_MEMMEM if you don't have memmem.
 #
+# Define NO_STRCHRNUL if you don't have strchrnul.
+#

Original patch lacked adding appropriate test to configure, i.e. something like below to configure.ac

#
# Define NO_STRCHRNUL if you don't have strchrnul. AC_CHECK_FUNC(strchrnul,
[NO_STRCHRNUL=],
[NO_STRCHRNUL=YesPlease]) AC_SUBST(NO_STRCHRNUL)

and the following line to config.mak.in

NO_STRCHRNUL=@NO_STRCHRNUL@

Quoted 1 line

This seems overly complicated. How about this instead?

[...]

Quoted 4 lines

I'm fairly much against forcing people to know what library functions they have in order to get software to compile properly. This is, imo, a neater solution, and also inlines the function as suggested by Dscho.

Wouldn't it be better to add ./configure check instead? See above.

Although I guess that people using ./configure to set compilation options (to generate config.mak.autogen) are minority...

Review

Quoted 11 lines
(quoted diff) +11 -0
+#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)
+# define strchrnul(s, c) gitstrchrnul(s, c)
+static inline char *gitstrchrnul(const char *s, int c)
+{
+       while (*s && *s != c)
+               s++;
+
+       return (char *)s;
+}
+#endif
+

This is good solution, although I'm not sure about the check itself. What if somebody has libc which is not glibc, but it does have strchrnul?

Quoted 16 lines
builtin-fetch--tool.c +1 -3
index 6a78517..ed60847 100644
@@ -435,9 +435,7 @@ static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu
                              cp++;
                      if (!*cp)
                              break;
-                     np = strchr(cp, '\n');
-                     if (!np)
-                             np = cp + strlen(cp);
+                     np = strchrnul(cp, '\n');
                      if (pass) {
                              lrr_list[i].line = cp;
                              lrr_list[i].name = cp + 41;

builtin-fetch--tool.c static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu · line 465

Quoted 10 lines
builtin-fetch--tool.c +1 -3
@@ -461,9 +459,7 @@ static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu
                      rref++;
              if (!*rref)
                      break;
-             next = strchr(rref, '\n');
-             if (!next)
-                     next = rref + strlen(rref);
+             next = strchrnul(rref, '\n');
              rreflen = next - rref;
 
              for (i = 0; i < lrr_count; i++) {

This IMHO should go to separate patch.

Signature · 3 lines
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
#15 lore raw
Quoted 5 lines · Jakub Narebski

[Cc: Andreas Ericsson <[email protected]>,
René Scharfe <[email protected]>,
Junio C Hamano <[email protected]>,
[email protected]]

I'm not sure what's up with this, but I didn't see this email on git@vger, so re-adding it to the Cc list now.

Quoted 22 lines

Original patch lacked adding appropriate test to configure, i.e. something like below to configure.ac

#
# Define NO_STRCHRNUL if you don't have strchrnul. AC_CHECK_FUNC(strchrnul,
[NO_STRCHRNUL=],
[NO_STRCHRNUL=YesPlease]) AC_SUBST(NO_STRCHRNUL)

and the following line to config.mak.in

NO_STRCHRNUL=@NO_STRCHRNUL@

Quoted 1 line

This seems overly complicated. How about this instead?

[...]

Quoted 4 lines

I'm fairly much against forcing people to know what library functions they have in order to get software to compile properly. This is, imo, a neater solution, and also inlines the function as suggested by Dscho.

Quoted 5 lines

Wouldn't it be better to add ./configure check instead? See above.

Although I guess that people using ./configure to set compilation options (to generate config.mak.autogen) are minority...

Perhaps. I know I don't anyway, and now it's become standard not to do so for a significant part of the git-tracking world.

Quoted 7 lines
Quoted 7 lines
(quoted diff) +7 -0
+#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)
+# define strchrnul(s, c) gitstrchrnul(s, c)
+static inline char *gitstrchrnul(const char *s, int c)
+{
+       while (*s && *s != c)
+               s++;
+
Quoted 9 lines

Review

Quoted 4 lines
(quoted diff) +4 -0
+       return (char *)s;
+}
+#endif
+

This is good solution, although I'm not sure about the check itself. What if somebody has libc which is not glibc, but it does have strchrnul?

They most likely fall into the minority that get to suffer from using code that's as fast as what's in there today, although a bit more readable. The glibc optimization is really only worthwhile for architectures where strchrnul()-like operations have microcode support, or when it's used on large strings.

YMMV. I suppose rewriting it as

#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 1)

# define HAVE_STRCHRNUL
#endif

#ifdef HAVE_STRCHRNUL
...

would work too, and will provide an easier way out for other fellas wanting to say "Hey, my favourite solaris libc has this too!". OTOH, that rewrite can be done when the first such case appears.

Quoted 4 lines

builtin-fetch--tool.c

Quoted 1 line
builtin-fetch--tool.c +0 -0

This IMHO should go to separate patch.

*shrug* Rene had it in his. Monkey see monkey do ;-)

Signature · 3 lines
Andreas Ericsson                   [email protected]
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231
#16 lore raw
Quoted 19 lines · Andreas Ericsson
Quoted 17 lines · Jakub Narebski

Review

Quoted 11 lines · René Scharfe
(quoted diff) +11 -0
+#if !defined(__GLIBC__) && !__GLIBC_PREREQ(2, 1)
+# define strchrnul(s, c) gitstrchrnul(s, c)
+static inline char *gitstrchrnul(const char *s, int c)
+{
+       while (*s && *s != c)
+               s++;
+
+       return (char *)s;
+}
+#endif
+

This is good solution, although I'm not sure about the check itself. What if somebody has libc which is not glibc, but it does have strchrnul?

Quoted 5 lines

They most likely fall into the minority that get to suffer from using code that's as fast as what's in there today, although a bit more readable. The glibc optimization is really only worthwhile for architectures where strchrnul()-like operations have microcode support, or when it's used on large strings.

If we end up using this solution, then adding test for strchrnul in the configure (configure.ac and config.mak.in) is not needed...

Quoted 3 lines

YMMV. I suppose rewriting it as

#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 1)

#if !defined(HAVE_STRCHRNUL) && \
     defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 1)
Quoted 9 lines
# define HAVE_STRCHRNUL
#endif

#ifdef HAVE_STRCHRNUL
...

would work too, and will provide an easier way out for other fellas wanting to say "Hey, my favourite solaris libc has this too!". OTOH, that rewrite can be done when the first such case appears.

...but if we end up using this version (be it HAVE_STRCHRNUL, or NO_STRCHRNUL), then test for strchrnul in ./configure is I think necessary.

Signature · 2 lines
Jakub Narebski
Poland
#17 lore raw
In reply to René Scharfe

Hi,

Quoted 61 lines · Ren? Scharfe
Makefile +8 -0
index 0d5590f..578c999 100644
@@ -30,6 +30,8 @@ all::
 #
 # Define NO_MEMMEM if you don't have memmem.
 #
+# Define NO_STRCHRNUL if you don't have strchrnul.
+#
 # Define NO_STRLCPY if you don't have strlcpy.
 #
 # Define NO_STRTOUMAX if you don't have strtoumax in the C library.
@@ -406,6 +408,7 @@ ifeq ($(uname_S),Darwin)
 	OLD_ICONV = UnfortunatelyYes
 	NO_STRLCPY = YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 endif
 ifeq ($(uname_S),SunOS)
 	NEEDS_SOCKET = YesPlease
@@ -413,6 +416,7 @@ ifeq ($(uname_S),SunOS)
 	SHELL_PATH = /bin/bash
 	NO_STRCASESTR = YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	NO_HSTRERROR = YesPlease
 	ifeq ($(uname_R),5.8)
 		NEEDS_LIBICONV = YesPlease
@@ -438,6 +442,7 @@ ifeq ($(uname_O),Cygwin)
 	NO_D_INO_IN_DIRENT = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	NO_SYMLINK_HEAD = YesPlease
 	NEEDS_LIBICONV = YesPlease
 	NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
@@ -452,12 +457,14 @@ endif
 ifeq ($(uname_S),FreeBSD)
 	NEEDS_LIBICONV = YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	BASIC_CFLAGS += -I/usr/local/include
 	BASIC_LDFLAGS += -L/usr/local/lib
 endif
 ifeq ($(uname_S),OpenBSD)
 	NO_STRCASESTR = YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	NEEDS_LIBICONV = YesPlease
 	BASIC_CFLAGS += -I/usr/local/include
 	BASIC_LDFLAGS += -L/usr/local/lib
@@ -473,6 +480,7 @@ endif
 ifeq ($(uname_S),AIX)
 	NO_STRCASESTR=YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	NO_STRLCPY = YesPlease
 	NEEDS_LIBICONV=YesPlease
 endif

Makefile ifeq ($(uname_S),IRIX64) · line 499

Quoted 7 lines
Makefile +1 -0
@@ -485,6 +493,7 @@ ifeq ($(uname_S),IRIX64)
 	NO_SETENV=YesPlease
 	NO_STRCASESTR=YesPlease
 	NO_MEMMEM = YesPlease
+	NO_STRCHRNUL = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_SOCKADDR_STORAGE=YesPlease
 	SHELL_PATH=/usr/gnu/bin/bash

Might be easier to define HAVE_STRCHRNUL ;-)

Quoted 6 lines
compat/strchrnul.c new file +0 -0
new file mode 100644
index 0000000..51839fe

compat/strchrnul.c line 8

Quoted 8 lines
compat/strchrnul.c new file +8 -0
@@ -0,0 +1,8 @@
+#include "../git-compat-util.h"
+
+char *gitstrchrnul(const char *s, int c)
+{
+	while (*s && *s != c)
+		s++;
+	return (char *)s;
+}

This is so short, I think it is even better to inline it.

Ciao,
Dscho