Bug 6530 [1] causes "git show v0.99.6~1" to fail with error "your
vsnprintf is broken". The workaround avoids that, but it corrupts
system error messages in non-C locales.

The bug has been fixed since 2.17. If git is built with glibc, it can
know running libc version with gnu_get_libc_version() and avoid the
workaround on fixed versions. The workaround is also dropped for all
non-glibc systems.

Tested on Gentoo Linux, glibc 2.17, amd64.

[1] http://sourceware.org/bugzilla/show_bug.cgi?id=6530

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 v2 removes USE_GLIBC and lets git-compat-util.h do the detection

 gettext.c         | 24 ++++++++++++++++--------
 git-compat-util.h | 11 +++++++++++
 2 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/gettext.c b/gettext.c
index 71e9545..772ab92 100644
--- a/gettext.c
+++ b/gettext.c
@@ -30,7 +30,7 @@ int use_gettext_poison(void)
 
 #ifndef NO_GETTEXT
 static const char *charset;
-static void init_gettext_charset(const char *domain)
+static void init_gettext_charset(const char *domain, int vsnprintf_broken)
 {
        /*
           This trick arranges for messages to be emitted in the user's
@@ -99,9 +99,7 @@ static void init_gettext_charset(const char *domain)
           $ LANGUAGE= LANG=de_DE.utf8 ./test
           test: Kein passendes Ger?t gefunden
 
-          In the long term we should probably see about getting that
-          vsnprintf bug in glibc fixed, and audit our code so it won't
-          fall apart under a non-C locale.
+          The vsnprintf bug has been fixed since 2.17.
 
           Then we could simply set LC_CTYPE from the environment, which would
           make things like the external perror(3) messages work.
@@ -112,21 +110,31 @@ static void init_gettext_charset(const char *domain)
           1. http://sourceware.org/bugzilla/show_bug.cgi?id=6530
           2. E.g. "Content-Type: text/plain; charset=UTF-8\n" in po/is.po
        */
-       setlocale(LC_CTYPE, "");
+       if (vsnprintf_broken)
+               setlocale(LC_CTYPE, "");
        charset = locale_charset();
        bind_textdomain_codeset(domain, charset);
-       setlocale(LC_CTYPE, "C");
+       if (vsnprintf_broken)
+               setlocale(LC_CTYPE, "C");
 }
 
 void git_setup_gettext(void)
 {
        const char *podir = getenv("GIT_TEXTDOMAINDIR");
+       const char *version = glibc_version();
+       int major, minor, vsnprintf_broken;
+
+       if (version && sscanf(version, "%d.%d", &major, &minor) == 2 &&
+           (major > 2 || (major == 2 && minor >= 17)))
+               vsnprintf_broken = 0;
+       else
+               vsnprintf_broken = 1;
 
        if (!podir)
                podir = GIT_LOCALE_PATH;
        bindtextdomain("git", podir);
-       setlocale(LC_MESSAGES, "");
-       init_gettext_charset("git");
+       setlocale(vsnprintf_broken ? LC_MESSAGES : LC_ALL, "");
+       init_gettext_charset("git", vsnprintf_broken);
        textdomain("git");
 }
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 7776f12..967f452 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -488,11 +488,22 @@ extern int git_vsnprintf(char *str, size_t maxsize,
 
 #ifdef __GLIBC_PREREQ
 #if __GLIBC_PREREQ(2, 1)
+#include <gnu/libc-version.h>
+#define glibc_version() gnu_get_libc_version()
 #define HAVE_STRCHRNUL
 #define HAVE_MEMPCPY
 #endif
 #endif
 
+#ifndef glibc_version
+#ifdef __GNU_LIBRARY__
+#define glibc_version() NULL
+#else
+/* non-glibc platforms, see git_setup_gettext() for "2.17" */
+#define glibc_version() "2.17"
+#endif
+#endif
+
 #ifndef HAVE_STRCHRNUL
 #define strchrnul gitstrchrnul
 static inline char *gitstrchrnul(const char *s, int c)
-- 
1.8.2.83.gc99314b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to