Skip to content

Commit 290c8e7

Browse files
mackylegitster
authored andcommitted
gettext.h: add parentheses around N_ expansion if supported
The gettext N_ macro is used to mark strings for translation without actually translating them. At runtime the string is expected to be passed to the gettext API for translation. If two N_ macro invocations appear next to each other with only whitespace (or nothing at all) between them, the two separate strings will be marked for translation, but the preprocessor will then silently combine the strings into one and at runtime the string passed to gettext will not match the strings that were translated so no translation will actually occur. Avoid this by adding parentheses around the expansion of the N_ macro so that instead of ending up with two adjacent strings that are then combined by the preprocessor, two adjacent strings surrounded by parentheses result instead which causes a compile error so the mistake can be quickly found and corrected. However, since these string literals are typically assigned to static variables and not all compilers support parenthesized string literal assignments, allow this to be controlled by the Makefile with the default only enabled when the compiler is known to support the syntax. For now only __GNUC__ enables this by default which covers both gcc and clang which should result in early detection of any adjacent N_ macros. Although the necessary tests make the affected files a bit less elegant, the benefit of avoiding propagation of a translation- marking error to all the translation teams thus creating extra work for them when the error is eventually detected and fixed would seem to outweigh the minor inelegance the additional configuration tests introduce. Helped-by: Junio C Hamano <[email protected]> Signed-off-by: Kyle J. McKay <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7ba4626 commit 290c8e7

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

Makefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,15 @@ all::
339339
# return NULL when it receives a bogus time_t.
340340
#
341341
# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime in librt.
342+
#
343+
# Define USE_PARENS_AROUND_GETTEXT_N to "yes" if your compiler happily
344+
# compiles the following initialization:
345+
#
346+
# static const char s[] = ("FOO");
347+
#
348+
# and define it to "no" if you need to remove the parentheses () around the
349+
# constant. The default is "auto", which means to use parentheses if your
350+
# compiler is detected to support it.
342351

343352
GIT-VERSION-FILE: FORCE
344353
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -946,6 +955,14 @@ ifneq (,$(SOCKLEN_T))
946955
BASIC_CFLAGS += -Dsocklen_t=$(SOCKLEN_T)
947956
endif
948957

958+
ifeq (yes,$(USE_PARENS_AROUND_GETTEXT_N))
959+
BASIC_CFLAGS += -DUSE_PARENS_AROUND_GETTEXT_N=1
960+
else
961+
ifeq (no,$(USE_PARENS_AROUND_GETTEXT_N))
962+
BASIC_CFLAGS += -DUSE_PARENS_AROUND_GETTEXT_N=0
963+
endif
964+
endif
965+
949966
ifeq ($(uname_S),Darwin)
950967
ifndef NO_FINK
951968
ifeq ($(shell test -d /sw/lib && echo y),y)

gettext.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,30 @@ const char *Q_(const char *msgid, const char *plu, unsigned long n)
6363
}
6464

6565
/* Mark msgid for translation but do not translate it. */
66+
#if !USE_PARENS_AROUND_GETTEXT_N
6667
#define N_(msgid) msgid
68+
#else
69+
/*
70+
* Strictly speaking, this will lead to invalid C when
71+
* used this way:
72+
* static const char s[] = N_("FOO");
73+
* which will expand to
74+
* static const char s[] = ("FOO");
75+
* and in valid C, the initializer on the right hand side must
76+
* be without the parentheses. But many compilers do accept it
77+
* as a language extension and it will allow us to catch mistakes
78+
* like:
79+
* static const char *msgs[] = {
80+
* N_("one")
81+
* N_("two"),
82+
* N_("three"),
83+
* NULL
84+
* };
85+
* (notice the missing comma on one of the lines) by forcing
86+
* a compilation error, because parenthesised ("one") ("two")
87+
* will not get silently turned into ("onetwo").
88+
*/
89+
#define N_(msgid) (msgid)
90+
#endif
6791

6892
#endif

git-compat-util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,4 +828,8 @@ struct tm *git_gmtime_r(const time_t *, struct tm *);
828828
#define gmtime_r git_gmtime_r
829829
#endif
830830

831+
#if !defined(USE_PARENS_AROUND_GETTEXT_N) && defined(__GNUC__)
832+
#define USE_PARENS_AROUND_GETTEXT_N 1
833+
#endif
834+
831835
#endif

0 commit comments

Comments
 (0)