From 67488754d5db6ca6e3a3fe538f196c1d435cf544 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 6 Mar 2025 07:17:21 -0800 Subject: [PATCH 01/17] pkg/libintl --- pkg/libintl/build.zig | 400 +++++++++++++ pkg/libintl/build.zig.zon | 11 + pkg/libintl/libgnuintl.h | 1 + pkg/libintl/libintl.h | 1168 +++++++++++++++++++++++++++++++++++++ 4 files changed, 1580 insertions(+) create mode 100644 pkg/libintl/build.zig create mode 100644 pkg/libintl/build.zig.zon create mode 100644 pkg/libintl/libgnuintl.h create mode 100644 pkg/libintl/libintl.h diff --git a/pkg/libintl/build.zig b/pkg/libintl/build.zig new file mode 100644 index 000000000..410587c46 --- /dev/null +++ b/pkg/libintl/build.zig @@ -0,0 +1,400 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const upstream = b.dependency("gettext", .{}); + + const config = b.addConfigHeader( + .{ .style = .{ + .autoconf = upstream.path("gettext-runtime/intl/config.h.in"), + } }, + .{ + // I mostly figured all of this out by actually running + // `./configure` on my Apple M3 MBP since that's the main + // target I'm interested in (macOS). We should adjust this as + // needed for other platforms. + .AC_APPLE_UNIVERSAL_BUILD = null, + .AVOID_ANY_THREADS = null, + .BITSIZEOF_PTRDIFF_T = null, + .BITSIZEOF_SIZE_T = null, + .BITSIZEOF_SIG_ATOMIC_T = null, + .BITSIZEOF_WCHAR_T = null, + .BITSIZEOF_WINT_T = null, + .CHECK_PRINTF_SAFE = 1, + .C_ALLOCA = null, + .DBL_EXPBIT0_BIT = 20, + .DBL_EXPBIT0_WORD = 1, + .DBL_SIGNBIT_BIT = null, + .DBL_SIGNBIT_WORD = null, + .ENABLE_NLS = 1, + .FLEXIBLE_ARRAY_MEMBER = {}, + .FLT_EXPBIT0_BIT = 23, + .FLT_EXPBIT0_WORD = 0, + .FLT_SIGNBIT_BIT = null, + .FLT_SIGNBIT_WORD = null, + .GNULIB_FSCANF = 1, + .GNULIB_LOCK = 1, + .GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU = null, + .GNULIB_SCANF = 1, + .GNULIB_TEST_FGETC = 1, + .GNULIB_TEST_FGETS = 1, + .GNULIB_TEST_FPRINTF = 1, + .GNULIB_TEST_FPUTC = 1, + .GNULIB_TEST_FPUTS = 1, + .GNULIB_TEST_FREAD = 1, + .GNULIB_TEST_FREE_POSIX = 1, + .GNULIB_TEST_FREXP = 1, + .GNULIB_TEST_FREXPL = 1, + .GNULIB_TEST_FSCANF = 1, + .GNULIB_TEST_FWRITE = 1, + .GNULIB_TEST_GETC = 1, + .GNULIB_TEST_GETCHAR = 1, + .GNULIB_TEST_GETCWD = 1, + .GNULIB_TEST_GETLOCALENAME_L_UNSAFE = 1, + .GNULIB_TEST_LOCALENAME_ENVIRON = 1, + .GNULIB_TEST_LOCALENAME_UNSAFE = 1, + .GNULIB_TEST_MBRTOWC = 1, + .GNULIB_TEST_MBSINIT = 1, + .GNULIB_TEST_MBSZERO = 1, + .GNULIB_TEST_MEMCHR = 1, + .GNULIB_TEST_PRINTF = 1, + .GNULIB_TEST_PTHREAD_ONCE = 1, + .GNULIB_TEST_PUTC = 1, + .GNULIB_TEST_PUTCHAR = 1, + .GNULIB_TEST_PUTS = 1, + .GNULIB_TEST_SCANF = 1, + .GNULIB_TEST_SETLOCALE_NULL = 1, + .GNULIB_TEST_SIGNBIT = 1, + .GNULIB_TEST_TSEARCH = 1, + .GNULIB_TEST_VFPRINTF = 1, + .GNULIB_TEST_VPRINTF = 1, + .GNULIB_TEST_WGETCWD = 1, + .GNULIB_TEST_WMEMCPY = 1, + .GNULIB_TEST_WMEMSET = 1, + .HAVE_AIX72_LOCALES = null, + .HAVE_ALLOCA = 1, + .HAVE_ALLOCA_H = 1, + .HAVE_ASPRINTF = 1, + .HAVE_BP_SYM_H = null, + .HAVE_BUILTIN_EXPECT = 1, + .HAVE_CFLOCALECOPYPREFERREDLANGUAGES = 1, + .HAVE_CFPREFERENCESCOPYAPPVALUE = 1, + .HAVE_COPYSIGNF_IN_LIBC = null, + .HAVE_COPYSIGNL_IN_LIBC = null, + .HAVE_COPYSIGN_IN_LIBC = null, + .HAVE_CRTDEFS_H = null, + .HAVE_C_BOOL = null, + .HAVE_C_STATIC_ASSERT = null, + .HAVE_DCGETTEXT = null, + .HAVE_DECL_ALARM = 1, + .HAVE_DECL_COPYSIGN = null, + .HAVE_DECL_COPYSIGNF = null, + .HAVE_DECL_COPYSIGNL = null, + .HAVE_DECL_ECVT = 1, + .HAVE_DECL_EXECVPE = 0, + .HAVE_DECL_FCLOSEALL = 0, + .HAVE_DECL_FCVT = 1, + .HAVE_DECL_FEOF_UNLOCKED = 1, + .HAVE_DECL_FGETS_UNLOCKED = 0, + .HAVE_DECL_GCVT = 1, + .HAVE_DECL_GETW = 1, + .HAVE_DECL_MBRTOWC = null, + .HAVE_DECL_MBSINIT = null, + .HAVE_DECL_PUTW = 1, + .HAVE_DECL_WCSDUP = 1, + .HAVE_DECL_WCSNLEN = 1, + .HAVE_DECL__SNPRINTF = 0, + .HAVE_DECL__SNWPRINTF = 0, + .HAVE_DLFCN_H = 1, + .HAVE_DUPLOCALE = 1, + .HAVE_FAKE_LOCALES = null, + .HAVE_FEATURES_H = null, + .HAVE_FREELOCALE = 1, + .HAVE_FREE_POSIX = null, + .HAVE_FREXPL_IN_LIBC = 1, + .HAVE_FREXP_IN_LIBC = 1, + .HAVE_GETCWD = 1, + .HAVE_GETEGID = 1, + .HAVE_GETEUID = 1, + .HAVE_GETGID = 1, + .HAVE_GETLOCALENAME_L = null, + .HAVE_GETPAGESIZE = 1, + .HAVE_GETTEXT = null, + .HAVE_GETUID = 1, + .HAVE_GOOD_USELOCALE = 1, + .HAVE_ICONV = null, + .HAVE_INTMAX_T = 1, + .HAVE_INTTYPES_H = 1, + .HAVE_INTTYPES_H_WITH_UINTMAX = 1, + .HAVE_ISNAND_IN_LIBC = 1, + .HAVE_ISNANF_IN_LIBC = 1, + .HAVE_ISNANL_IN_LIBC = 1, + .HAVE_LANGINFO_CODESET = 1, + .HAVE_LANGINFO_H = 1, + .HAVE_LC_MESSAGES = 1, + .HAVE_LDEXPL_IN_LIBC = 1, + .HAVE_LDEXP_IN_LIBC = 1, + .HAVE_LIMITS_H = 1, + .HAVE_LONG_LONG_INT = 1, + .HAVE_MAP_ANONYMOUS = 1, + .HAVE_MATH_H = 1, + .HAVE_MBRTOWC = 1, + .HAVE_MBSINIT = 1, + .HAVE_MBSTATE_T = 1, + .HAVE_MEMPCPY = null, + .HAVE_MINIX_CONFIG_H = null, + .HAVE_MMAP = 1, + .HAVE_MPROTECT = 1, + .HAVE_MUNMAP = 1, + .HAVE_NAMELESS_LOCALES = null, + .HAVE_NEWLOCALE = 1, + .HAVE_NL_LANGINFO = 1, + .HAVE_POSIX_PRINTF = 1, + .HAVE_PTHREAD_API = 1, + .HAVE_PTHREAD_H = 1, + .HAVE_PTHREAD_MUTEX_RECURSIVE = 1, + .HAVE_PTHREAD_RWLOCK = 1, + .HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER = 1, + .HAVE_PTHREAD_SPINLOCK_T = null, + .HAVE_PTHREAD_T = 1, + .HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1, + .HAVE_SCHED_H = 1, + .HAVE_SEARCH_H = 1, + .HAVE_SIGNED_SIG_ATOMIC_T = null, + .HAVE_SIGNED_WCHAR_T = null, + .HAVE_SIGNED_WINT_T = null, + .HAVE_SNPRINTF = 1, + .HAVE_SNPRINTF_RETVAL_C99 = 1, + .HAVE_SNPRINTF_TRUNCATION_C99 = 1, + .HAVE_SOLARIS114_LOCALES = null, + .HAVE_STDBOOL_H = 1, + .HAVE_STDINT_H = 1, + .HAVE_STDINT_H_WITH_UINTMAX = 1, + .HAVE_STDIO_H = 1, + .HAVE_STDLIB_H = 1, + .HAVE_STPCPY = 1, + .HAVE_STRCASECMP = 1, + .HAVE_STRINGS_H = 1, + .HAVE_STRING_H = 1, + .HAVE_STRNLEN = 1, + .HAVE_SWPRINTF = 1, + .HAVE_SYMLINK = 1, + .HAVE_SYS_BITYPES_H = null, + .HAVE_SYS_INTTYPES_H = null, + .HAVE_SYS_MMAN_H = 1, + .HAVE_SYS_PARAM_H = 1, + .HAVE_SYS_SINGLE_THREADED_H = null, + .HAVE_SYS_STAT_H = 1, + .HAVE_SYS_TIME_H = 1, + .HAVE_SYS_TYPES_H = 1, + .HAVE_THRD_CREATE = null, + .HAVE_THREADS_H = null, + .HAVE_TSEARCH = 1, + .HAVE_TWALK = 1, + .HAVE_UNISTD_H = 1, + .HAVE_UNSIGNED_LONG_LONG_INT = 1, + .HAVE_USELOCALE = 1, + .HAVE_VASNPRINTF = null, + .HAVE_VISIBILITY = 1, + .HAVE_WCHAR_H = 1, + .HAVE_WCRTOMB = 1, + .HAVE_WCSLEN = 1, + .HAVE_WCSNLEN = 1, + .HAVE_WEAK_SYMBOLS = null, + .HAVE_WINDOWS_LOCALE_T = null, + .HAVE_WINT_T = 1, + .HAVE_WORKING_O_NOATIME = 1, + .HAVE_WORKING_O_NOFOLLOW = 1, + .HAVE_WORKING_SWPRINTF = null, + .HAVE_WORKING_USELOCALE = 1, + .HAVE_WPRINTF = 1, + .HAVE_XLOCALE_H = 1, + .HAVE___FSETLOCKING = null, + .HAVE___HEADER_INLINE = 1, + .ICONV_CONST = {}, + .LDBL_EXPBIT0_BIT = 20, + .LDBL_EXPBIT0_WORD = 1, + .LDBL_SIGNBIT_BIT = null, + .LDBL_SIGNBIT_WORD = null, + .LOCALENAME_ENHANCE_LOCALE_FUNCS = null, + .LT_OBJDIR = ".libs/", + .MAP_ANONYMOUS = null, + .MBRTOWC_EMPTY_INPUT_BUG = null, + .MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ = null, + .MBRTOWC_NULL_ARG1_BUG = null, + .MBRTOWC_NULL_ARG2_BUG = null, + .MBRTOWC_NUL_RETVAL_BUG = null, + .MBRTOWC_RETVAL_BUG = null, + .MBRTOWC_STORES_INCOMPLETE_BUG = null, + .__USE_MINGW_ANSI_STDIO = 1, + .MUSL_LIBC = null, + .NEED_PRINTF_DIRECTIVE_A = 1, + .NEED_PRINTF_DIRECTIVE_B = 1, + .NEED_PRINTF_DIRECTIVE_F = null, + .NEED_PRINTF_DIRECTIVE_LC = null, + .NEED_PRINTF_DIRECTIVE_LS = null, + .NEED_PRINTF_DOUBLE = 1, + .NEED_PRINTF_ENOMEM = 1, + .NEED_PRINTF_FLAG_ALT_PRECISION_ZERO = null, + .NEED_PRINTF_FLAG_GROUPING = null, + .NEED_PRINTF_FLAG_LEFTADJUST = null, + .NEED_PRINTF_FLAG_ZERO = null, + .NEED_PRINTF_INFINITE_DOUBLE = null, + .NEED_PRINTF_INFINITE_LONG_DOUBLE = null, + .NEED_PRINTF_LONG_DOUBLE = 1, + .NEED_PRINTF_UNBOUNDED_PRECISION = null, + .NEED_WPRINTF_DIRECTIVE_C = 1, + .NEED_WPRINTF_DIRECTIVE_LA = null, + .NEED_WPRINTF_DIRECTIVE_LC = 1, + .PACKAGE = "libintl", + .PACKAGE_BUGREPORT = "bug-gettext@gnu.org", + .PACKAGE_NAME = "libintl", + .PACKAGE_STRING = "libintl 0.24", + .PACKAGE_TARNAME = "libintl", + .PACKAGE_URL = "", + .PACKAGE_VERSION = "0.24", + .PTHREAD_IN_USE_DETECTION_HARD = null, + .PTRDIFF_T_SUFFIX = null, + .REPLACE_VASNPRINTF = null, + .SETLOCALE_NULL_ALL_MTSAFE = 0, + .SETLOCALE_NULL_ONE_MTSAFE = 1, + .SIG_ATOMIC_T_SUFFIX = null, + .SIZE_MAX = null, + .SIZE_T_SUFFIX = null, + .STACK_DIRECTION = null, + .STDC_HEADERS = 1, + .USE_ISOC_AND_POSIX_THREADS = null, + .USE_ISOC_THREADS = null, + .USE_POSIX_THREADS = 1, + .USE_POSIX_THREADS_FROM_LIBC = null, + .USE_POSIX_THREADS_WEAK = null, + ._ALL_SOURCE = 1, + ._DARWIN_C_SOURCE = 1, + .__EXTENSIONS__ = 1, + ._GNU_SOURCE = 1, + ._HPUX_ALT_XOPEN_SOCKET_API = 1, + ._MINIX = null, + ._NETBSD_SOURCE = 1, + ._OPENBSD_SOURCE = 1, + ._POSIX_SOURCE = null, + ._POSIX_1_SOURCE = null, + ._POSIX_PTHREAD_SEMANTICS = 1, + .__STDC_WANT_IEC_60559_ATTRIBS_EXT__ = 1, + .__STDC_WANT_IEC_60559_BFP_EXT__ = 1, + .__STDC_WANT_IEC_60559_DFP_EXT__ = 1, + .__STDC_WANT_IEC_60559_EXT__ = 1, + .__STDC_WANT_IEC_60559_FUNCS_EXT__ = 1, + .__STDC_WANT_IEC_60559_TYPES_EXT__ = 1, + .__STDC_WANT_LIB_EXT2__ = 1, + .__STDC_WANT_MATH_SPEC_FUNCS__ = 1, + ._TANDEM_SOURCE = 1, + ._XOPEN_SOURCE = null, + .USE_WINDOWS_THREADS = null, + .VERSION = "0.24", + .WCHAR_T_SUFFIX = null, + .WINT_T_SUFFIX = null, + .WORDS_BIGENDIAN = null, + ._ISOC11_SOURCE = null, + ._LCONV_C99 = null, + ._LINUX_SOURCE_COMPAT = 1, + ._USE_STD_STAT = 1, + .__STDC_CONSTANT_MACROS = null, + .__STDC_LIMIT_MACROS = null, + .frexp = null, + .frexpl = null, + .@"inline" = null, + .intmax_t = null, + .mbrtowc = null, + .mbsinit = null, + .mbstate_t = null, + .memchr = null, + .mode_t = null, + .pid_t = null, + .ptrdiff_t = null, + .restrict = null, + //.restrict = "__restrict__", + .rpl_fgetc = null, + .rpl_fgets = null, + .rpl_fprintf = null, + .rpl_fputc = null, + .rpl_fputs = null, + .rpl_fread = null, + .rpl_frexp = null, + .rpl_frexpl = null, + .rpl_fscanf = null, + .rpl_fwrite = null, + .rpl_mbrtowc = null, + .rpl_mbsinit = null, + .rpl_memchr = null, + .rpl_tdelete = null, + .rpl_tfind = null, + .rpl_tsearch = null, + .rpl_twalk = null, + .rpl_vfprintf = null, + .size_t = null, + .ssize_t = null, + .tdelete = null, + .tfind = null, + .tsearch = null, + .twalk = null, + }, + ); + + var flags = std.ArrayList([]const u8).init(b.allocator); + defer flags.deinit(); + try flags.appendSlice(&.{ + "-DHAVE_CONFIG_H", + "-DLOCALEDIR=\"\"", + }); + + { + const lib = b.addStaticLibrary(.{ + .name = "intl", + .target = target, + .optimize = optimize, + }); + lib.linkLibC(); + lib.addIncludePath(b.path("")); + lib.addIncludePath(upstream.path("gettext-runtime/intl")); + lib.addIncludePath(upstream.path("gettext-runtime/intl/gnulib-lib")); + lib.addConfigHeader(config); + lib.addCSourceFiles(.{ + .root = upstream.path("gettext-runtime/intl"), + .files = srcs, + .flags = flags.items, + }); + + lib.installHeader(b.path("libintl.h"), "libintl.h"); + b.installArtifact(lib); + } +} + +const srcs: []const []const u8 = &.{ + "bindtextdom.c", + "dcgettext.c", + "dcigettext.c", + "dcngettext.c", + "dgettext.c", + "dngettext.c", + "explodename.c", + "finddomain.c", + "gettext.c", + "hash-string.c", + "intl-compat.c", + "l10nflist.c", + "langprefs.c", + "loadmsgcat.c", + "localealias.c", + "log.c", + "ngettext.c", + "osdep.c", + "plural-exp.c", + "plural.c", + "printf.c", + "setlocale.c", + "textdomain.c", + "version.c", + "compat.c", +}; diff --git a/pkg/libintl/build.zig.zon b/pkg/libintl/build.zig.zon new file mode 100644 index 000000000..e5f630726 --- /dev/null +++ b/pkg/libintl/build.zig.zon @@ -0,0 +1,11 @@ +.{ + .name = "libintl", + .version = "0.24.0", + .paths = .{""}, + .dependencies = .{ + .gettext = .{ + .url = "https://deps.files.ghostty.org/gettext-0.24.tar.gz", + .hash = "1220f870c853529233ea64a108acaaa81f8d06d7ff4b66c76930be7d78d508aff7a2", + }, + }, +} diff --git a/pkg/libintl/libgnuintl.h b/pkg/libintl/libgnuintl.h new file mode 100644 index 000000000..c972210fa --- /dev/null +++ b/pkg/libintl/libgnuintl.h @@ -0,0 +1 @@ +#include "libintl.h" diff --git a/pkg/libintl/libintl.h b/pkg/libintl/libintl.h new file mode 100644 index 000000000..f49301816 --- /dev/null +++ b/pkg/libintl/libintl.h @@ -0,0 +1,1168 @@ +/* Message catalogs for internationalization. + Copyright (C) 1995-2025 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#ifndef _LIBINTL_H +#define _LIBINTL_H 1 + +#include +#if (defined __APPLE__ && defined __MACH__) && 1 +#include +#endif + +/* The LC_MESSAGES locale category is the category used by the functions + gettext() and dgettext(). It is specified in POSIX, but not in ANSI C. + On systems that don't define it, use an arbitrary value instead. + On Solaris, defines __LOCALE_H (or _LOCALE_H in Solaris 2.5) + then includes (i.e. this file!) and then only defines + LC_MESSAGES. To avoid a redefinition warning, don't define LC_MESSAGES + in this case. */ +#if !defined LC_MESSAGES && \ + !(defined __LOCALE_H || (defined _LOCALE_H && defined __sun)) +#define LC_MESSAGES 1729 +#endif + +/* We define an additional symbol to signal that we use the GNU + implementation of gettext. */ +#define __USE_GNU_GETTEXT 1 + +/* Provide information about the supported file formats. Returns the + maximum minor revision number supported for a given major revision. */ +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) \ + ((major) == 0 || (major) == 1 ? 1 : -1) + +/* Resolve a platform specific conflict on DJGPP. GNU gettext takes + precedence over _conio_gettext. */ +#ifdef __DJGPP__ +#undef gettext +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Version number: (major<<16) + (minor<<8) + subminor */ +#define LIBINTL_VERSION 0x001800 +extern int libintl_version; + +/* We redirect the functions to those prefixed with "libintl_". This is + necessary, because some systems define gettext/textdomain/... in the C + library (namely, Solaris 2.4 and newer, and GNU libc 2.0 and newer). + If we used the unprefixed names, there would be cases where the + definition in the C library would override the one in the libintl.so + shared library. Recall that on ELF systems, the symbols are looked + up in the following order: + 1. in the executable, + 2. in the shared libraries specified on the link command line, in order, + 3. in the dependencies of the shared libraries specified on the link + command line, + 4. in the dlopen()ed shared libraries, in the order in which they were + dlopen()ed. + The definition in the C library would override the one in libintl.so if + either + * -lc is given on the link command line and -lintl isn't, or + * -lc is given on the link command line before -lintl, or + * libintl.so is a dependency of a dlopen()ed shared library but not + linked to the executable at link time. + Since Solaris gettext() behaves differently than GNU gettext(), this + would be unacceptable. + + For the redirection, three mechanisms are available: + * _INTL_REDIRECT_ASM uses a function declaration with 'asm', that + specifies a different symbol at the linker level than at the C level. + * _INTL_REDIRECT_INLINE uses an inline function definition. In C, + we use 'static inline' to force the override. In C++, it is better + to use 'inline' without 'static'. But since the override is only + effective if the inlining happens, we need to use + __attribute__ ((__always_inline__)), which is supported in g++ >= 3.1 + and clang. MSVC has a similar keyword __forceinline (see + ), + but it has an effect only when optimizing is enabled, and there is no + preprocessor macro that tells us whether optimizing is enabled. + * _INTL_REDIRECT_MACROS uses C macros. + The drawbacks are: + * _INTL_REDIRECT_ASM and _INTL_REDIRECT_INLINE don't work when the + function has an inline function definition in a system header file; + this mostly affects mingw and MSVC. In these cases, + _INTL_REDIRECT_MACROS is the only mechanism that works. + * _INTL_REDIRECT_MACROS can interfere with symbols used in structs and + classes (especially in C++, but also in C). For example, Qt has a class + with an 'asprintf' member, and our '#define asprintf libintl_asprintf' + triggers a compilation error. + * _INTL_REDIRECT_INLINE in C mode has the effect that each function's + address, such as &gettext, is different in each compilation unit. + */ + +/* _INTL_FORCE_INLINE ensures inlining of a function, even when not + optimizing. */ +/* Applies to: functions. */ +/* Supported by g++ >= 3.1 and clang. Actually needed for g++ < 4.0. */ +#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 1) > 3) || \ + defined __clang__ +#define _INTL_HAS_FORCE_INLINE +#define _INTL_FORCE_INLINE __attribute__((__always_inline__)) +#else +#define _INTL_FORCE_INLINE +#endif + +/* The user can define _INTL_REDIRECT_INLINE or _INTL_REDIRECT_MACROS. + If he doesn't, we choose the method. */ +#if !(defined _INTL_REDIRECT_INLINE || defined _INTL_REDIRECT_MACROS) +#if defined __GNUC__ && __GNUC__ >= 2 && \ + !(defined __APPLE_CC__ && __APPLE_CC__ > 1) && !defined __MINGW32__ && \ + !(__GNUC__ == 2 && defined _AIX) && \ + (defined __STDC__ || defined __cplusplus) +#define _INTL_REDIRECT_ASM +#else +#if defined __cplusplus && defined _INTL_HAS_FORCE_INLINE +#define _INTL_REDIRECT_INLINE +#else +#define _INTL_REDIRECT_MACROS +#endif +#endif +#endif +/* Auxiliary macros. */ +#ifdef _INTL_REDIRECT_ASM +#define _INTL_ASM(cname) __asm__(_INTL_ASMNAME(__USER_LABEL_PREFIX__, #cname)) +#define _INTL_ASMNAME(prefix, cnamestring) _INTL_STRINGIFY(prefix) cnamestring +#define _INTL_STRINGIFY(prefix) #prefix +#else +#define _INTL_ASM(cname) +#endif + +/* _INTL_MAY_RETURN_STRING_ARG(n) declares that the given function may return + its n-th argument literally. This enables GCC to warn for example about + printf (gettext ("foo %y")). */ +#if ((defined __GNUC__ && __GNUC__ >= 3) || defined __clang__) && \ + !(defined __APPLE_CC__ && __APPLE_CC__ > 1 && \ + !(defined __clang__ && __clang__ && __clang_major__ >= 3) && \ + defined __cplusplus) +#define _INTL_MAY_RETURN_STRING_ARG(n) __attribute__((__format_arg__(n))) +#else +#define _INTL_MAY_RETURN_STRING_ARG(n) +#endif + +/* _INTL_ATTRIBUTE_FORMAT ((ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK)) + declares that the STRING-INDEXth function argument is a format string of + style ARCHETYPE, which is one of: + printf, gnu_printf + scanf, gnu_scanf, + strftime, gnu_strftime, + strfmon, + or the same thing prefixed and suffixed with '__'. + If FIRST-TO-CHECK is not 0, arguments starting at FIRST-TO_CHECK + are suitable for the format string. */ +/* Applies to: functions. */ +#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 7) > 2) || \ + defined __clang__ +#define _INTL_ATTRIBUTE_FORMAT(spec) __attribute__((__format__ spec)) +#else +#define _INTL_ATTRIBUTE_FORMAT(spec) +#endif + +/* _INTL_ATTRIBUTE_SPEC_PRINTF_STANDARD + An __attribute__ __format__ specifier for a function that takes a format + string and arguments, where the format string directives are the ones + standardized by ISO C99 and POSIX. */ +/* __gnu_printf__ is supported in GCC >= 4.4. */ +#if defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 4) > 4 +#define _INTL_ATTRIBUTE_SPEC_PRINTF_STANDARD __gnu_printf__ +#else +#define _INTL_ATTRIBUTE_SPEC_PRINTF_STANDARD __printf__ +#endif + +/* _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD + indicates to GCC that the function takes a format string and arguments, + where the format string directives are the ones standardized by ISO C99 + and POSIX. */ +#define _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(formatstring_parameter, \ + first_argument) \ + _INTL_ATTRIBUTE_FORMAT((_INTL_ATTRIBUTE_SPEC_PRINTF_STANDARD, \ + formatstring_parameter, first_argument)) + +/* _INTL_ARG_NONNULL ((N1, N2,...)) declares that the arguments N1, N2,... + must not be NULL. */ +/* Applies to: functions. */ +#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || \ + defined __clang__ +#define _INTL_ARG_NONNULL(params) __attribute__((__nonnull__ params)) +#else +#define _INTL_ARG_NONNULL(params) +#endif + +/* Look up MSGID in the current default message catalog for the current + LC_MESSAGES locale. If not found, returns MSGID itself (the default + text). */ +#ifdef _INTL_REDIRECT_INLINE +extern char* libintl_gettext(const char* __msgid) + _INTL_MAY_RETURN_STRING_ARG(1); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_MAY_RETURN_STRING_ARG(1) char* gettext(const char* __msgid) { + return libintl_gettext(__msgid); +} +#else +#ifdef _INTL_REDIRECT_MACROS +#define gettext libintl_gettext +#endif +extern char* gettext(const char* __msgid) _INTL_ASM(libintl_gettext) + _INTL_MAY_RETURN_STRING_ARG(1); +#endif + +/* Look up MSGID in the DOMAINNAME message catalog for the current + LC_MESSAGES locale. */ +#ifdef _INTL_REDIRECT_INLINE +extern char* libintl_dgettext(const char* __domainname, const char* __msgid) + _INTL_MAY_RETURN_STRING_ARG(2); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_MAY_RETURN_STRING_ARG(2) char* dgettext(const char* __domainname, + const char* __msgid) { + return libintl_dgettext(__domainname, __msgid); +} +#else +#ifdef _INTL_REDIRECT_MACROS +#define dgettext libintl_dgettext +#endif +extern char* dgettext(const char* __domainname, const char* __msgid) + _INTL_ASM(libintl_dgettext) _INTL_MAY_RETURN_STRING_ARG(2); +#endif + +/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY + locale. */ +#ifdef _INTL_REDIRECT_INLINE +extern char* libintl_dcgettext(const char* __domainname, + const char* __msgid, + int __category) _INTL_MAY_RETURN_STRING_ARG(2); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_MAY_RETURN_STRING_ARG(2) char* dcgettext(const char* __domainname, + const char* __msgid, + int __category) { + return libintl_dcgettext(__domainname, __msgid, __category); +} +#else +#ifdef _INTL_REDIRECT_MACROS +#define dcgettext libintl_dcgettext +#endif +extern char* dcgettext(const char* __domainname, + const char* __msgid, + int __category) _INTL_ASM(libintl_dcgettext) + _INTL_MAY_RETURN_STRING_ARG(2); +#endif + +/* Similar to 'gettext' but select the plural form corresponding to the + number N. */ +#ifdef _INTL_REDIRECT_INLINE +extern char* libintl_ngettext(const char* __msgid1, + const char* __msgid2, + unsigned long int __n) + _INTL_MAY_RETURN_STRING_ARG(1) _INTL_MAY_RETURN_STRING_ARG(2); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_MAY_RETURN_STRING_ARG(1) + _INTL_MAY_RETURN_STRING_ARG(2) char* ngettext(const char* __msgid1, + const char* __msgid2, + unsigned long int __n) { + return libintl_ngettext(__msgid1, __msgid2, __n); +} +#else +#ifdef _INTL_REDIRECT_MACROS +#define ngettext libintl_ngettext +#endif +extern char* ngettext(const char* __msgid1, + const char* __msgid2, + unsigned long int __n) _INTL_ASM(libintl_ngettext) + _INTL_MAY_RETURN_STRING_ARG(1) _INTL_MAY_RETURN_STRING_ARG(2); +#endif + +/* Similar to 'dgettext' but select the plural form corresponding to the + number N. */ +#ifdef _INTL_REDIRECT_INLINE +extern char* libintl_dngettext(const char* __domainname, + const char* __msgid1, + const char* __msgid2, + unsigned long int __n) + _INTL_MAY_RETURN_STRING_ARG(2) _INTL_MAY_RETURN_STRING_ARG(3); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_MAY_RETURN_STRING_ARG(2) + _INTL_MAY_RETURN_STRING_ARG(3) char* dngettext(const char* __domainname, + const char* __msgid1, + const char* __msgid2, + unsigned long int __n) { + return libintl_dngettext(__domainname, __msgid1, __msgid2, __n); +} +#else +#ifdef _INTL_REDIRECT_MACROS +#define dngettext libintl_dngettext +#endif +extern char* dngettext(const char* __domainname, + const char* __msgid1, + const char* __msgid2, + unsigned long int __n) _INTL_ASM(libintl_dngettext) + _INTL_MAY_RETURN_STRING_ARG(2) _INTL_MAY_RETURN_STRING_ARG(3); +#endif + +/* Similar to 'dcgettext' but select the plural form corresponding to the + number N. */ +#ifdef _INTL_REDIRECT_INLINE +extern char* libintl_dcngettext(const char* __domainname, + const char* __msgid1, + const char* __msgid2, + unsigned long int __n, + int __category) _INTL_MAY_RETURN_STRING_ARG(2) + _INTL_MAY_RETURN_STRING_ARG(3); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_MAY_RETURN_STRING_ARG(2) _INTL_MAY_RETURN_STRING_ARG( + 3) char* dcngettext(const char* __domainname, + const char* __msgid1, + const char* __msgid2, + unsigned long int __n, + int __category) { + return libintl_dcngettext(__domainname, __msgid1, __msgid2, __n, __category); +} +#else +#ifdef _INTL_REDIRECT_MACROS +#define dcngettext libintl_dcngettext +#endif +extern char* dcngettext(const char* __domainname, + const char* __msgid1, + const char* __msgid2, + unsigned long int __n, + int __category) _INTL_ASM(libintl_dcngettext) + _INTL_MAY_RETURN_STRING_ARG(2) _INTL_MAY_RETURN_STRING_ARG(3); +#endif + +/* Set the current default message catalog to DOMAINNAME. + If DOMAINNAME is null, return the current default. + If DOMAINNAME is "", reset to the default of "messages". */ +#ifdef _INTL_REDIRECT_INLINE +extern char* libintl_textdomain(const char* __domainname); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE char* + textdomain(const char* __domainname) { + return libintl_textdomain(__domainname); +} +#else +#ifdef _INTL_REDIRECT_MACROS +#define textdomain libintl_textdomain +#endif +extern char* textdomain(const char* __domainname) _INTL_ASM(libintl_textdomain); +#endif + +/* Specify that the DOMAINNAME message catalog will be found + in DIRNAME rather than in the system locale data base. */ +#ifdef _INTL_REDIRECT_INLINE +extern char* libintl_bindtextdomain(const char* __domainname, + const char* __dirname); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE char* + bindtextdomain(const char* __domainname, const char* __dirname) { + return libintl_bindtextdomain(__domainname, __dirname); +} +#else +#ifdef _INTL_REDIRECT_MACROS +#define bindtextdomain libintl_bindtextdomain +#endif +extern char* bindtextdomain(const char* __domainname, const char* __dirname) + _INTL_ASM(libintl_bindtextdomain); +#endif + +#if defined _WIN32 && !defined __CYGWIN__ +/* Specify that the DOMAINNAME message catalog will be found + in WDIRNAME rather than in the system locale data base. */ +#ifdef _INTL_REDIRECT_INLINE +extern wchar_t* libintl_wbindtextdomain(const char* __domainname, + const wchar_t* __wdirname); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE wchar_t* + wbindtextdomain(const char* __domainname, const wchar_t* __wdirname) { + return libintl_wbindtextdomain(__domainname, __wdirname); +} +#else +#ifdef _INTL_REDIRECT_MACROS +#define wbindtextdomain libintl_wbindtextdomain +#endif +extern wchar_t* wbindtextdomain(const char* __domainname, + const wchar_t* __wdirname) + _INTL_ASM(libintl_wbindtextdomain); +#endif +#endif + +/* Specify the character encoding in which the messages from the + DOMAINNAME message catalog will be returned. */ +#ifdef _INTL_REDIRECT_INLINE +extern char* libintl_bind_textdomain_codeset(const char* __domainname, + const char* __codeset); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE char* + bind_textdomain_codeset(const char* __domainname, const char* __codeset) { + return libintl_bind_textdomain_codeset(__domainname, __codeset); +} +#else +#ifdef _INTL_REDIRECT_MACROS +#define bind_textdomain_codeset libintl_bind_textdomain_codeset +#endif +extern char* bind_textdomain_codeset(const char* __domainname, + const char* __codeset) + _INTL_ASM(libintl_bind_textdomain_codeset); +#endif + +/* Support for format strings with positions in *printf(), following the + POSIX/XSI specification. + Note: These replacements for the *printf() functions are visible only + in source files that #include or #include "gettext.h". + Packages that use *printf() in source files that don't refer to _() + or gettext() but for which the format string could be the return value + of _() or gettext() need to add this #include. Oh well. */ + +/* Note: In C++ mode, it is not sufficient to redefine a symbol at the + preprocessor macro level, such as + #define sprintf libintl_sprintf + Some programs may reference std::sprintf after including . + Therefore we must make sure that std::libintl_sprintf is defined and + identical to ::libintl_sprintf. + The user can define _INTL_CXX_NO_CLOBBER_STD_NAMESPACE to avoid this. + In such cases, they will not benefit from the overrides when using + the 'std' namespace, and they will need to do the references to the + 'std' namespace *before* including or "gettext.h". */ + +#if !1 + +#include +#include + +/* Get va_list. */ +#if (defined __STDC__ && __STDC__) || defined __cplusplus || defined _MSC_VER +#include +#else +#include +#endif + +#if !((defined fprintf && defined _GL_STDIO_H) || \ + defined GNULIB_overrides_fprintf) /* don't override gnulib */ +#if defined _INTL_REDIRECT_INLINE && !(defined __MINGW32__ || defined _MSC_VER) +extern int libintl_vfprintf(FILE*, const char*, va_list) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) _INTL_ARG_NONNULL((1, 2)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 3) + _INTL_ARG_NONNULL((1, 2)) int fprintf(FILE* __stream, + const char* __format, + ...) { + va_list __args; + int __ret; + va_start(__args, __format); + __ret = libintl_vfprintf(__stream, __format, __args); + va_end(__args); + return __ret; +} +#elif !defined _INTL_NO_DEFINE_MACRO_FPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || defined _MSC_VER +#undef fprintf +#define fprintf libintl_fprintf +#endif +extern int fprintf(FILE*, const char*, ...) _INTL_ASM(libintl_fprintf) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 3) _INTL_ARG_NONNULL((1, 2)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || \ + defined _MSC_VER) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_fprintf; +} +#endif +#endif +#endif +#if !((defined vfprintf && defined _GL_STDIO_H) || \ + defined GNULIB_overrides_vfprintf) /* don't override gnulib */ +#if defined _INTL_REDIRECT_INLINE && !(defined __MINGW32__ || defined _MSC_VER) +extern int libintl_vfprintf(FILE*, const char*, va_list) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) _INTL_ARG_NONNULL((1, 2)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) + _INTL_ARG_NONNULL((1, 2)) int vfprintf(FILE* __stream, + const char* __format, + va_list __args) { + return libintl_vfprintf(__stream, __format, __args); +} +#elif !defined _INTL_NO_DEFINE_MACRO_VFPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || defined _MSC_VER +#undef vfprintf +#define vfprintf libintl_vfprintf +#endif +extern int vfprintf(FILE*, const char*, va_list) _INTL_ASM(libintl_vfprintf) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) _INTL_ARG_NONNULL((1, 2)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || \ + defined _MSC_VER) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_vfprintf; +} +#endif +#endif +#endif + +#if !((defined printf && defined _GL_STDIO_H) || \ + defined GNULIB_overrides_printf) /* don't override gnulib */ +#if defined _INTL_REDIRECT_INLINE && !(defined __MINGW32__ || defined _MSC_VER) +extern int libintl_vprintf(const char*, va_list) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(1, 0) _INTL_ARG_NONNULL((1)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(1, 2) + _INTL_ARG_NONNULL((1)) int printf(const char* __format, ...) { + va_list __args; + int __ret; + va_start(__args, __format); + __ret = libintl_vprintf(__format, __args); + va_end(__args); + return __ret; +} +#elif !defined _INTL_NO_DEFINE_MACRO_PRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || defined _MSC_VER +#undef printf +#if defined __NetBSD__ || defined __BEOS__ || defined __CYGWIN__ || \ + defined __MINGW32__ +/* Don't break __attribute__((format(printf,M,N))). + This redefinition is only possible because the libc in NetBSD, Cygwin, + mingw does not have a function __printf__. + Alternatively, we could have done this redirection only when compiling with + __GNUC__, together with a symbol redirection: + extern int printf (const char *, ...) + __asm__ (#__USER_LABEL_PREFIX__ "libintl_printf"); + But doing it now would introduce a binary incompatibility with already + distributed versions of libintl on these systems. */ +#define libintl_printf __printf__ +#endif +#define printf libintl_printf +#endif +extern int printf(const char*, ...) _INTL_ASM(libintl_printf) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(1, 2) _INTL_ARG_NONNULL((1)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || \ + defined _MSC_VER) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_printf; +} +#endif +#endif +#endif +#if !((defined vprintf && defined _GL_STDIO_H) || \ + defined GNULIB_overrides_vprintf) /* don't override gnulib */ +#if defined _INTL_REDIRECT_INLINE && !(defined __MINGW32__ || defined _MSC_VER) +extern int libintl_vprintf(const char*, va_list) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(1, 0) _INTL_ARG_NONNULL((1)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(1, 0) + _INTL_ARG_NONNULL((1)) int vprintf(const char* __format, + va_list __args) { + return libintl_vprintf(__format, __args); +} +#elif !defined _INTL_NO_DEFINE_MACRO_VPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || defined _MSC_VER +#undef vprintf +#define vprintf libintl_vprintf +#endif +extern int vprintf(const char*, va_list) _INTL_ASM(libintl_vprintf) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(1, 0) _INTL_ARG_NONNULL((1)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || \ + defined _MSC_VER) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_vprintf; +} +#endif +#endif +#endif + +#if !((defined sprintf && defined _GL_STDIO_H) || \ + defined GNULIB_overrides_sprintf) /* don't override gnulib */ +#if defined _INTL_REDIRECT_INLINE && !(defined __MINGW32__ || defined _MSC_VER) +extern int libintl_vsprintf(char*, const char*, va_list) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) _INTL_ARG_NONNULL((1, 2)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 3) + _INTL_ARG_NONNULL((1, 2)) int sprintf(char* __result, + const char* __format, + ...) { + va_list __args; + int __ret; + va_start(__args, __format); + __ret = libintl_vsprintf(__result, __format, __args); + va_end(__args); + return __ret; +} +#elif !defined _INTL_NO_DEFINE_MACRO_SPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || defined _MSC_VER +#undef sprintf +#define sprintf libintl_sprintf +#endif +extern int sprintf(char*, const char*, ...) _INTL_ASM(libintl_sprintf) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 3) _INTL_ARG_NONNULL((1, 2)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || \ + defined _MSC_VER) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_sprintf; +} +#endif +#endif +#endif +#if !((defined vsprintf && defined _GL_STDIO_H) || \ + defined GNULIB_overrides_vsprintf) /* don't override gnulib */ +#if defined _INTL_REDIRECT_INLINE && !(defined __MINGW32__ || defined _MSC_VER) +extern int libintl_vsprintf(char*, const char*, va_list) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) _INTL_ARG_NONNULL((1, 2)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) + _INTL_ARG_NONNULL((1, 2)) int vsprintf(char* __result, + const char* __format, + va_list __args) { + return libintl_vsprintf(__result, __format, __args); +} +#elif !defined _INTL_NO_DEFINE_MACRO_VSPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || defined _MSC_VER +#undef vsprintf +#define vsprintf libintl_vsprintf +#endif +extern int vsprintf(char*, const char*, va_list) _INTL_ASM(libintl_vsprintf) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) _INTL_ARG_NONNULL((1, 2)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__ || \ + defined _MSC_VER) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_vsprintf; +} +#endif +#endif +#endif + +#if 1 + +#if !((defined snprintf && defined _GL_STDIO_H) || \ + defined GNULIB_overrides_snprintf) /* don't override gnulib */ +#if defined _INTL_REDIRECT_INLINE && !defined __MINGW32__ +extern int libintl_vsnprintf(char*, size_t, const char*, va_list) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(3, 0) _INTL_ARG_NONNULL((3)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(3, 4) + _INTL_ARG_NONNULL((3)) int snprintf(char* __result, + size_t __maxlen, + const char* __format, + ...) { + va_list __args; + int __ret; + va_start(__args, __format); + __ret = libintl_vsnprintf(__result, __maxlen, __format, __args); + va_end(__args); + return __ret; +} +#elif !defined _INTL_NO_DEFINE_MACRO_SNPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ +#undef snprintf +#define snprintf libintl_snprintf +#endif +extern int snprintf(char*, size_t, const char*, ...) _INTL_ASM(libintl_snprintf) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(3, 4) _INTL_ARG_NONNULL((3)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_snprintf; +} +#endif +#endif +#endif +#if !((defined vsnprintf && defined _GL_STDIO_H) || \ + defined GNULIB_overrides_vsnprintf) /* don't override gnulib */ +#if defined _INTL_REDIRECT_INLINE && !defined __MINGW32__ +extern int libintl_vsnprintf(char*, size_t, const char*, va_list) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(3, 0) _INTL_ARG_NONNULL((3)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(3, 0) + _INTL_ARG_NONNULL((3)) int vsnprintf(char* __result, + size_t __maxlen, + const char* __format, + va_list __args) { + return libintl_vsnprintf(__result, __maxlen, __format, __args); +} +#elif !defined _INTL_NO_DEFINE_MACRO_VSNPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ +#undef vsnprintf +#define vsnprintf libintl_vsnprintf +#endif +extern int vsnprintf(char*, size_t, const char*, va_list) + _INTL_ASM(libintl_vsnprintf) _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(3, 0) + _INTL_ARG_NONNULL((3)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_vsnprintf; +} +#endif +#endif +#endif + +#endif + +#if 1 + +#if !((defined asprintf && defined _GL_STDIO_H) || \ + defined GNULIB_overrides_asprintf) /* don't override gnulib */ +#if defined _INTL_REDIRECT_INLINE && !defined __MINGW32__ +extern int libintl_vasprintf(char**, const char*, va_list) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) _INTL_ARG_NONNULL((1, 2)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 3) + _INTL_ARG_NONNULL((1, 2)) int asprintf(char** __result, + const char* __format, + ...) { + va_list __args; + int __ret; + va_start(__args, __format); + __ret = libintl_vasprintf(__result, __format, __args); + va_end(__args); + return __ret; +} +#elif !defined _INTL_NO_DEFINE_MACRO_ASPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ +#undef asprintf +#define asprintf libintl_asprintf +#endif +extern int asprintf(char**, const char*, ...) _INTL_ASM(libintl_asprintf) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 3) _INTL_ARG_NONNULL((1, 2)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_asprintf; +} +#endif +#endif +#endif +#if !((defined vasprintf && defined _GL_STDIO_H) || \ + defined GNULIB_overrides_vasprintf) /* don't override gnulib */ +#if defined _INTL_REDIRECT_INLINE && !defined __MINGW32__ +extern int libintl_vasprintf(char**, const char*, va_list) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) _INTL_ARG_NONNULL((1, 2)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) + _INTL_ARG_NONNULL((1, 2)) int vasprintf(char** __result, + const char* __format, + va_list __args) { + return libintl_vasprintf(__result, __format, __args); +} +#elif !defined _INTL_NO_DEFINE_MACRO_VASPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ +#undef vasprintf +#define vasprintf libintl_vasprintf +#endif +extern int vasprintf(char**, const char*, va_list) _INTL_ASM(libintl_vasprintf) + _INTL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 0) _INTL_ARG_NONNULL((1, 2)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_vasprintf; +} +#endif +#endif +#endif + +#endif + +#if 1 + +#if defined _INTL_REDIRECT_INLINE && !defined __MINGW32__ +extern int libintl_vfwprintf(FILE*, const wchar_t*, va_list) + _INTL_ARG_NONNULL((1, 2)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ARG_NONNULL((1, 2)) int fwprintf(FILE* __stream, + const wchar_t* __format, + ...) { + va_list __args; + int __ret; + va_start(__args, __format); + __ret = libintl_vfwprintf(__stream, __format, __args); + va_end(__args); + return __ret; +} +#elif !defined _INTL_NO_DEFINE_MACRO_FWPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ +#undef fwprintf +#define fwprintf libintl_fwprintf +#endif +extern int fwprintf(FILE*, const wchar_t*, ...) _INTL_ASM(libintl_fwprintf) + _INTL_ARG_NONNULL((1, 2)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_fwprintf; +} +#endif +#endif +#if defined _INTL_REDIRECT_INLINE && !defined __MINGW32__ +extern int libintl_vfwprintf(FILE*, const wchar_t*, va_list) + _INTL_ARG_NONNULL((1, 2)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ARG_NONNULL((1, 2)) int vfwprintf(FILE* __stream, + const wchar_t* __format, + va_list __args) { + return libintl_vfwprintf(__stream, __format, __args); +} +#elif !defined _INTL_NO_DEFINE_MACRO_VFWPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ +#undef vfwprintf +#define vfwprintf libintl_vfwprintf +#endif +extern int vfwprintf(FILE*, const wchar_t*, va_list) + _INTL_ASM(libintl_vfwprintf) _INTL_ARG_NONNULL((1, 2)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_vfwprintf; +} +#endif +#endif + +#if defined _INTL_REDIRECT_INLINE && !defined __MINGW32__ +extern int libintl_vwprintf(const wchar_t*, va_list) _INTL_ARG_NONNULL((1)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ARG_NONNULL((1)) int wprintf(const wchar_t* __format, ...) { + va_list __args; + int __ret; + va_start(__args, __format); + __ret = libintl_vwprintf(__format, __args); + va_end(__args); + return __ret; +} +#elif !defined _INTL_NO_DEFINE_MACRO_WPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ +#undef wprintf +#define wprintf libintl_wprintf +#endif +extern int wprintf(const wchar_t*, ...) _INTL_ASM(libintl_wprintf) + _INTL_ARG_NONNULL((1)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_wprintf; +} +#endif +#endif +#if defined _INTL_REDIRECT_INLINE && !defined __MINGW32__ +extern int libintl_vwprintf(const wchar_t*, va_list) _INTL_ARG_NONNULL((1)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ARG_NONNULL((1)) int vwprintf(const wchar_t* __format, + va_list __args) { + return libintl_vwprintf(__format, __args); +} +#elif !defined _INTL_NO_DEFINE_MACRO_VWPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ +#undef vwprintf +#define vwprintf libintl_vwprintf +#endif +extern int vwprintf(const wchar_t*, va_list) _INTL_ASM(libintl_vwprintf) + _INTL_ARG_NONNULL((1)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_vwprintf; +} +#endif +#endif + +#if defined _INTL_REDIRECT_INLINE && !defined __MINGW32__ +extern int libintl_vswprintf(wchar_t*, size_t, const wchar_t*, va_list) + _INTL_ARG_NONNULL((1, 3)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ARG_NONNULL((1, 3)) int swprintf(wchar_t* __result, + size_t __maxlen, + const wchar_t* __format, + ...) { + va_list __args; + int __ret; + va_start(__args, __format); + __ret = libintl_vswprintf(__result, __maxlen, __format, __args); + va_end(__args); + return __ret; +} +#elif !defined _INTL_NO_DEFINE_MACRO_SWPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ +#undef swprintf +#define swprintf libintl_swprintf +#endif +extern int swprintf(wchar_t*, size_t, const wchar_t*, ...) + _INTL_ASM(libintl_swprintf) _INTL_ARG_NONNULL((1, 3)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_swprintf; +} +#endif +#endif +#if defined _INTL_REDIRECT_INLINE && !defined __MINGW32__ +extern int libintl_vswprintf(wchar_t*, size_t, const wchar_t*, va_list) + _INTL_ARG_NONNULL((1, 3)); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE + _INTL_ARG_NONNULL((1, 3)) int vswprintf(wchar_t* __result, + size_t __maxlen, + const wchar_t* __format, + va_list __args) { + return libintl_vswprintf(__result, __maxlen, __format, __args); +} +#elif !defined _INTL_NO_DEFINE_MACRO_VSWPRINTF +#if defined _INTL_REDIRECT_MACROS || defined __MINGW32__ +#undef vswprintf +#define vswprintf libintl_vswprintf +#endif +extern int vswprintf(wchar_t*, size_t, const wchar_t*, va_list) + _INTL_ASM(libintl_vswprintf) _INTL_ARG_NONNULL((1, 3)); +#if (defined _INTL_REDIRECT_MACROS || defined __MINGW32__) && \ + defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_vswprintf; +} +#endif +#endif + +#endif + +#endif + +/* Support for retrieving the name of a locale_t object. */ +#if 0 + +#ifndef GNULIB_defined_newlocale /* don't override gnulib */ +#ifdef _INTL_REDIRECT_INLINE +extern locale_t libintl_newlocale(int, const char*, locale_t); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE locale_t + newlocale(int __category_mask, const char* __name, locale_t __base) { + return libintl_newlocale(__category_mask, __name, __base); +} +#elif !defined _INTL_NO_DEFINE_MACRO_NEWLOCALE +#ifdef _INTL_REDIRECT_MACROS +#undef newlocale +#define newlocale libintl_newlocale +#endif +extern locale_t newlocale(int, const char*, locale_t) + _INTL_ASM(libintl_newlocale); +#if defined _INTL_REDIRECT_MACROS && defined __cplusplus && \ + !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_newlocale; +} +#endif +#endif +#endif + +#ifndef GNULIB_defined_duplocale /* don't override gnulib */ +#ifdef _INTL_REDIRECT_INLINE +extern locale_t libintl_duplocale(locale_t); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE locale_t + duplocale(locale_t __locale) { + return libintl_duplocale(__locale); +} +#elif !defined _INTL_NO_DEFINE_MACRO_DUPLOCALE +#ifdef _INTL_REDIRECT_MACROS +#undef duplocale +#define duplocale libintl_duplocale +#endif +extern locale_t duplocale(locale_t) _INTL_ASM(libintl_duplocale); +#if defined _INTL_REDIRECT_MACROS && defined __cplusplus && \ + !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_duplocale; +} +#endif +#endif +#endif + +#ifndef GNULIB_defined_freelocale /* don't override gnulib */ +#ifdef _INTL_REDIRECT_INLINE +extern void libintl_freelocale(locale_t); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE void + freelocale(locale_t __locale) { + libintl_freelocale(__locale); +} +#elif !defined _INTL_NO_DEFINE_MACRO_FREELOCALE +#ifdef _INTL_REDIRECT_MACROS +#undef freelocale +#define freelocale libintl_freelocale +#endif +extern void freelocale(locale_t) _INTL_ASM(libintl_freelocale); +#if defined _INTL_REDIRECT_MACROS && defined __cplusplus && \ + !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_freelocale; +} +#endif +#endif +#endif + +#endif + +/* Support for the locale chosen by the user. */ +#if (defined __APPLE__ && defined __MACH__) || defined _WIN32 || \ + defined __CYGWIN__ + +#ifndef GNULIB_defined_setlocale /* don't override gnulib */ +#ifdef _INTL_REDIRECT_INLINE +extern char* libintl_setlocale(int, const char*); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE char* + setlocale(int __category, const char* __locale) { + return libintl_setlocale(__category, __locale); +} +#elif !defined _INTL_NO_DEFINE_MACRO_SETLOCALE +#ifdef _INTL_REDIRECT_MACROS +#undef setlocale +#define setlocale libintl_setlocale +#endif +extern char* setlocale(int, const char*) _INTL_ASM(libintl_setlocale); +#if defined _INTL_REDIRECT_MACROS && defined __cplusplus && \ + !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_setlocale; +} +#endif +#endif +#endif + +#if 1 + +/* Declare newlocale() only if the system headers define the 'locale_t' type. */ +#if !(defined __CYGWIN__ && !defined LC_ALL_MASK) +#ifdef _INTL_REDIRECT_INLINE +extern locale_t libintl_newlocale(int, const char*, locale_t); +#ifndef __cplusplus +static +#endif + inline _INTL_FORCE_INLINE locale_t + newlocale(int __category_mask, const char* __name, locale_t __base) { + return libintl_newlocale(__category_mask, __name, __base); +} +#elif !defined _INTL_NO_DEFINE_MACRO_NEWLOCALE +#ifdef _INTL_REDIRECT_MACROS +#undef newlocale +#define newlocale libintl_newlocale +#endif +extern locale_t newlocale(int, const char*, locale_t) + _INTL_ASM(libintl_newlocale); +#if defined _INTL_REDIRECT_MACROS && defined __cplusplus && \ + !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE +namespace std { +using ::libintl_newlocale; +} +#endif +#endif +#endif + +#endif + +#endif + +/* Support for relocatable packages. */ + +/* Sets the original and the current installation prefix of the package. + Relocation simply replaces a pathname starting with the original prefix + by the corresponding pathname with the current prefix instead. Both + prefixes should be directory names without trailing slash (i.e. use "" + instead of "/"). */ +#define libintl_set_relocation_prefix libintl_set_relocation_prefix +extern void libintl_set_relocation_prefix(const char* orig_prefix, + const char* curr_prefix); + +#ifdef __cplusplus +} +#endif + +#endif /* libintl.h */ From dd95f727ec785ba288fd874fb8b1c3a9b182db95 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 6 Mar 2025 07:23:00 -0800 Subject: [PATCH 02/17] build: add libintl for macOS builds --- build.zig.zon | 1 + pkg/libintl/build.zig | 14 ++++++++++++-- pkg/libintl/build.zig.zon | 2 ++ src/build/SharedDeps.zig | 11 +++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 76142b4aa..4e69cb393 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -63,6 +63,7 @@ .gtk4_layer_shell = .{ .path = "./pkg/gtk4-layer-shell" }, .harfbuzz = .{ .path = "./pkg/harfbuzz" }, .highway = .{ .path = "./pkg/highway" }, + .libintl = .{ .path = "./pkg/libintl" }, .libpng = .{ .path = "./pkg/libpng" }, .macos = .{ .path = "./pkg/macos" }, .oniguruma = .{ .path = "./pkg/oniguruma" }, diff --git a/pkg/libintl/build.zig b/pkg/libintl/build.zig index 410587c46..bf2e14150 100644 --- a/pkg/libintl/build.zig +++ b/pkg/libintl/build.zig @@ -359,6 +359,12 @@ pub fn build(b: *std.Build) !void { lib.addIncludePath(b.path("")); lib.addIncludePath(upstream.path("gettext-runtime/intl")); lib.addIncludePath(upstream.path("gettext-runtime/intl/gnulib-lib")); + + if (target.result.isDarwin()) { + const apple_sdk = @import("apple_sdk"); + try apple_sdk.addPaths(b, &lib.root_module); + } + lib.addConfigHeader(config); lib.addCSourceFiles(.{ .root = upstream.path("gettext-runtime/intl"), @@ -389,12 +395,16 @@ const srcs: []const []const u8 = &.{ "localealias.c", "log.c", "ngettext.c", - "osdep.c", "plural-exp.c", "plural.c", - "printf.c", "setlocale.c", "textdomain.c", "version.c", "compat.c", + + // Not needed for macOS, but we might need them for other platforms. + // If we expand this to support other platforms, we should uncomment + // these. + // "osdep.c", + // "printf.c", }; diff --git a/pkg/libintl/build.zig.zon b/pkg/libintl/build.zig.zon index e5f630726..216bf1bbb 100644 --- a/pkg/libintl/build.zig.zon +++ b/pkg/libintl/build.zig.zon @@ -7,5 +7,7 @@ .url = "https://deps.files.ghostty.org/gettext-0.24.tar.gz", .hash = "1220f870c853529233ea64a108acaaa81f8d06d7ff4b66c76930be7d78d508aff7a2", }, + + .apple_sdk = .{ .path = "../apple-sdk" }, }, } diff --git a/src/build/SharedDeps.zig b/src/build/SharedDeps.zig index d592aee70..28eb7fa68 100644 --- a/src/build/SharedDeps.zig +++ b/src/build/SharedDeps.zig @@ -381,6 +381,17 @@ pub fn add( if (self.config.renderer == .opengl) { step.linkFramework("OpenGL"); } + + // Apple platforms do not include libc libintl so we bundle it. + // This is LGPL but since our source code is open source we are + // in compliance with the LGPL since end users can modify this + // build script to replace the bundled libintl with their own. + const libintl_dep = b.dependency("libintl", .{ + .target = target, + .optimize = optimize, + }); + step.linkLibrary(libintl_dep.artifact("intl")); + try static_libs.append(libintl_dep.artifact("intl").getEmittedBin()); } // cimgui From cb8085ab729f8197304aa6750668484d5f6f0340 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 6 Mar 2025 09:40:01 -0800 Subject: [PATCH 03/17] global state initializes i18n --- src/global.zig | 5 +++++ src/os/i18n.zig | 38 ++++++++++++++++++++++++++++++++++++++ src/os/main.zig | 1 + 3 files changed, 44 insertions(+) create mode 100644 src/os/i18n.zig diff --git a/src/global.zig b/src/global.zig index b9af5983d..c93b35fa0 100644 --- a/src/global.zig +++ b/src/global.zig @@ -172,6 +172,11 @@ pub const GlobalState = struct { // hereafter can use this cached value. self.resources_dir = try internal_os.resourcesDir(self.alloc); errdefer if (self.resources_dir) |dir| self.alloc.free(dir); + + // Setup i18n + if (self.resources_dir) |v| internal_os.i18n.init(v) catch |err| { + std.log.warn("failed to init i18n, translations will not be available err={}", .{err}); + }; } /// Cleans up the global state. This doesn't _need_ to be called but diff --git a/src/os/i18n.zig b/src/os/i18n.zig new file mode 100644 index 000000000..d6124cac5 --- /dev/null +++ b/src/os/i18n.zig @@ -0,0 +1,38 @@ +const std = @import("std"); +const build_config = @import("../build_config.zig"); + +pub const InitError = error{ + InvalidResourcesDir, + OutOfMemory, +}; + +/// Initialize i18n support for the application. This should be +/// called automatically by the global state initialization +/// in global.zig. +/// +/// This calls `bindtextdomain` for gettext with the proper directory +/// of translations. This does NOT call `textdomain` as we don't +/// want to set the domain for the entire application since this is also +/// used by libghostty. +pub fn init(resources_dir: []const u8) InitError!void { + // Our resources dir is always nested below the share dir that + // is standard for translations. + const share_dir = std.fs.path.dirname(resources_dir) orelse + return error.InvalidResourcesDir; + + // Build our locale path + var buf: [std.fs.max_path_bytes]u8 = undefined; + const path = std.fmt.bufPrintZ(&buf, "{s}/locale", .{share_dir}) catch + return error.OutOfMemory; + + // Bind our bundle ID to the given locale path + _ = bindtextdomain(build_config.bundle_id, path.ptr) orelse + return error.OutOfMemory; +} + +// Manually include function definitions for the gettext functions +// as libintl.h isn't always easily available (e.g. in musl) +extern fn bindtextdomain(domainname: [*:0]const u8, dirname: [*:0]const u8) ?[*:0]const u8; +extern fn textdomain(domainname: [*:0]const u8) ?[*:0]const u8; +pub extern fn gettext(msgid: [*:0]const u8) [*:0]const u8; +pub const _ = gettext; diff --git a/src/os/main.zig b/src/os/main.zig index cb9355931..7c961ea13 100644 --- a/src/os/main.zig +++ b/src/os/main.zig @@ -17,6 +17,7 @@ const resourcesdir = @import("resourcesdir.zig"); pub const args = @import("args.zig"); pub const cgroup = @import("cgroup.zig"); pub const hostname = @import("hostname.zig"); +pub const i18n = @import("i18n.zig"); pub const passwd = @import("passwd.zig"); pub const xdg = @import("xdg.zig"); pub const windows = @import("windows.zig"); From e8c20b55016b5f13bdfc7cbbfabfbaa903a3ee3a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 6 Mar 2025 10:10:21 -0800 Subject: [PATCH 04/17] pkg/libintl: fix missing symbols --- pkg/libintl/build.zig | 365 +------ pkg/libintl/config.h | 2370 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2398 insertions(+), 337 deletions(-) create mode 100644 pkg/libintl/config.h diff --git a/pkg/libintl/build.zig b/pkg/libintl/build.zig index bf2e14150..de7ba2b47 100644 --- a/pkg/libintl/build.zig +++ b/pkg/libintl/build.zig @@ -1,3 +1,21 @@ +//! Provides libintl for macOS. +//! +//! IMPORTANT: This is only for macOS. We could support other platforms +//! if/when we need to but generally Linux provides libintl in libc. +//! Windows we'll have to figure out when we get there. +//! +//! Since this is only for macOS, there's a lot of hardcoded stuff +//! here that assumes macOS. For example, I generated the config.h +//! on my own machine (a Mac) and then copied it here. This isn't +//! ideal since we should do the same detection that gettext's configure +//! script does, but its quite a bit of work to do that. +//! +//! UPGRADING: If you need to upgrade gettext, then the only thing to +//! really watch out for is the xlocale.h include we added manually +//! at the end of config.h. The comment there notes why. When we upgrade +//! we should audit our config.h and make sure we add that back (if we +//! have to). + const std = @import("std"); pub fn build(b: *std.Build) !void { @@ -6,342 +24,6 @@ pub fn build(b: *std.Build) !void { const upstream = b.dependency("gettext", .{}); - const config = b.addConfigHeader( - .{ .style = .{ - .autoconf = upstream.path("gettext-runtime/intl/config.h.in"), - } }, - .{ - // I mostly figured all of this out by actually running - // `./configure` on my Apple M3 MBP since that's the main - // target I'm interested in (macOS). We should adjust this as - // needed for other platforms. - .AC_APPLE_UNIVERSAL_BUILD = null, - .AVOID_ANY_THREADS = null, - .BITSIZEOF_PTRDIFF_T = null, - .BITSIZEOF_SIZE_T = null, - .BITSIZEOF_SIG_ATOMIC_T = null, - .BITSIZEOF_WCHAR_T = null, - .BITSIZEOF_WINT_T = null, - .CHECK_PRINTF_SAFE = 1, - .C_ALLOCA = null, - .DBL_EXPBIT0_BIT = 20, - .DBL_EXPBIT0_WORD = 1, - .DBL_SIGNBIT_BIT = null, - .DBL_SIGNBIT_WORD = null, - .ENABLE_NLS = 1, - .FLEXIBLE_ARRAY_MEMBER = {}, - .FLT_EXPBIT0_BIT = 23, - .FLT_EXPBIT0_WORD = 0, - .FLT_SIGNBIT_BIT = null, - .FLT_SIGNBIT_WORD = null, - .GNULIB_FSCANF = 1, - .GNULIB_LOCK = 1, - .GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU = null, - .GNULIB_SCANF = 1, - .GNULIB_TEST_FGETC = 1, - .GNULIB_TEST_FGETS = 1, - .GNULIB_TEST_FPRINTF = 1, - .GNULIB_TEST_FPUTC = 1, - .GNULIB_TEST_FPUTS = 1, - .GNULIB_TEST_FREAD = 1, - .GNULIB_TEST_FREE_POSIX = 1, - .GNULIB_TEST_FREXP = 1, - .GNULIB_TEST_FREXPL = 1, - .GNULIB_TEST_FSCANF = 1, - .GNULIB_TEST_FWRITE = 1, - .GNULIB_TEST_GETC = 1, - .GNULIB_TEST_GETCHAR = 1, - .GNULIB_TEST_GETCWD = 1, - .GNULIB_TEST_GETLOCALENAME_L_UNSAFE = 1, - .GNULIB_TEST_LOCALENAME_ENVIRON = 1, - .GNULIB_TEST_LOCALENAME_UNSAFE = 1, - .GNULIB_TEST_MBRTOWC = 1, - .GNULIB_TEST_MBSINIT = 1, - .GNULIB_TEST_MBSZERO = 1, - .GNULIB_TEST_MEMCHR = 1, - .GNULIB_TEST_PRINTF = 1, - .GNULIB_TEST_PTHREAD_ONCE = 1, - .GNULIB_TEST_PUTC = 1, - .GNULIB_TEST_PUTCHAR = 1, - .GNULIB_TEST_PUTS = 1, - .GNULIB_TEST_SCANF = 1, - .GNULIB_TEST_SETLOCALE_NULL = 1, - .GNULIB_TEST_SIGNBIT = 1, - .GNULIB_TEST_TSEARCH = 1, - .GNULIB_TEST_VFPRINTF = 1, - .GNULIB_TEST_VPRINTF = 1, - .GNULIB_TEST_WGETCWD = 1, - .GNULIB_TEST_WMEMCPY = 1, - .GNULIB_TEST_WMEMSET = 1, - .HAVE_AIX72_LOCALES = null, - .HAVE_ALLOCA = 1, - .HAVE_ALLOCA_H = 1, - .HAVE_ASPRINTF = 1, - .HAVE_BP_SYM_H = null, - .HAVE_BUILTIN_EXPECT = 1, - .HAVE_CFLOCALECOPYPREFERREDLANGUAGES = 1, - .HAVE_CFPREFERENCESCOPYAPPVALUE = 1, - .HAVE_COPYSIGNF_IN_LIBC = null, - .HAVE_COPYSIGNL_IN_LIBC = null, - .HAVE_COPYSIGN_IN_LIBC = null, - .HAVE_CRTDEFS_H = null, - .HAVE_C_BOOL = null, - .HAVE_C_STATIC_ASSERT = null, - .HAVE_DCGETTEXT = null, - .HAVE_DECL_ALARM = 1, - .HAVE_DECL_COPYSIGN = null, - .HAVE_DECL_COPYSIGNF = null, - .HAVE_DECL_COPYSIGNL = null, - .HAVE_DECL_ECVT = 1, - .HAVE_DECL_EXECVPE = 0, - .HAVE_DECL_FCLOSEALL = 0, - .HAVE_DECL_FCVT = 1, - .HAVE_DECL_FEOF_UNLOCKED = 1, - .HAVE_DECL_FGETS_UNLOCKED = 0, - .HAVE_DECL_GCVT = 1, - .HAVE_DECL_GETW = 1, - .HAVE_DECL_MBRTOWC = null, - .HAVE_DECL_MBSINIT = null, - .HAVE_DECL_PUTW = 1, - .HAVE_DECL_WCSDUP = 1, - .HAVE_DECL_WCSNLEN = 1, - .HAVE_DECL__SNPRINTF = 0, - .HAVE_DECL__SNWPRINTF = 0, - .HAVE_DLFCN_H = 1, - .HAVE_DUPLOCALE = 1, - .HAVE_FAKE_LOCALES = null, - .HAVE_FEATURES_H = null, - .HAVE_FREELOCALE = 1, - .HAVE_FREE_POSIX = null, - .HAVE_FREXPL_IN_LIBC = 1, - .HAVE_FREXP_IN_LIBC = 1, - .HAVE_GETCWD = 1, - .HAVE_GETEGID = 1, - .HAVE_GETEUID = 1, - .HAVE_GETGID = 1, - .HAVE_GETLOCALENAME_L = null, - .HAVE_GETPAGESIZE = 1, - .HAVE_GETTEXT = null, - .HAVE_GETUID = 1, - .HAVE_GOOD_USELOCALE = 1, - .HAVE_ICONV = null, - .HAVE_INTMAX_T = 1, - .HAVE_INTTYPES_H = 1, - .HAVE_INTTYPES_H_WITH_UINTMAX = 1, - .HAVE_ISNAND_IN_LIBC = 1, - .HAVE_ISNANF_IN_LIBC = 1, - .HAVE_ISNANL_IN_LIBC = 1, - .HAVE_LANGINFO_CODESET = 1, - .HAVE_LANGINFO_H = 1, - .HAVE_LC_MESSAGES = 1, - .HAVE_LDEXPL_IN_LIBC = 1, - .HAVE_LDEXP_IN_LIBC = 1, - .HAVE_LIMITS_H = 1, - .HAVE_LONG_LONG_INT = 1, - .HAVE_MAP_ANONYMOUS = 1, - .HAVE_MATH_H = 1, - .HAVE_MBRTOWC = 1, - .HAVE_MBSINIT = 1, - .HAVE_MBSTATE_T = 1, - .HAVE_MEMPCPY = null, - .HAVE_MINIX_CONFIG_H = null, - .HAVE_MMAP = 1, - .HAVE_MPROTECT = 1, - .HAVE_MUNMAP = 1, - .HAVE_NAMELESS_LOCALES = null, - .HAVE_NEWLOCALE = 1, - .HAVE_NL_LANGINFO = 1, - .HAVE_POSIX_PRINTF = 1, - .HAVE_PTHREAD_API = 1, - .HAVE_PTHREAD_H = 1, - .HAVE_PTHREAD_MUTEX_RECURSIVE = 1, - .HAVE_PTHREAD_RWLOCK = 1, - .HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER = 1, - .HAVE_PTHREAD_SPINLOCK_T = null, - .HAVE_PTHREAD_T = 1, - .HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1, - .HAVE_SCHED_H = 1, - .HAVE_SEARCH_H = 1, - .HAVE_SIGNED_SIG_ATOMIC_T = null, - .HAVE_SIGNED_WCHAR_T = null, - .HAVE_SIGNED_WINT_T = null, - .HAVE_SNPRINTF = 1, - .HAVE_SNPRINTF_RETVAL_C99 = 1, - .HAVE_SNPRINTF_TRUNCATION_C99 = 1, - .HAVE_SOLARIS114_LOCALES = null, - .HAVE_STDBOOL_H = 1, - .HAVE_STDINT_H = 1, - .HAVE_STDINT_H_WITH_UINTMAX = 1, - .HAVE_STDIO_H = 1, - .HAVE_STDLIB_H = 1, - .HAVE_STPCPY = 1, - .HAVE_STRCASECMP = 1, - .HAVE_STRINGS_H = 1, - .HAVE_STRING_H = 1, - .HAVE_STRNLEN = 1, - .HAVE_SWPRINTF = 1, - .HAVE_SYMLINK = 1, - .HAVE_SYS_BITYPES_H = null, - .HAVE_SYS_INTTYPES_H = null, - .HAVE_SYS_MMAN_H = 1, - .HAVE_SYS_PARAM_H = 1, - .HAVE_SYS_SINGLE_THREADED_H = null, - .HAVE_SYS_STAT_H = 1, - .HAVE_SYS_TIME_H = 1, - .HAVE_SYS_TYPES_H = 1, - .HAVE_THRD_CREATE = null, - .HAVE_THREADS_H = null, - .HAVE_TSEARCH = 1, - .HAVE_TWALK = 1, - .HAVE_UNISTD_H = 1, - .HAVE_UNSIGNED_LONG_LONG_INT = 1, - .HAVE_USELOCALE = 1, - .HAVE_VASNPRINTF = null, - .HAVE_VISIBILITY = 1, - .HAVE_WCHAR_H = 1, - .HAVE_WCRTOMB = 1, - .HAVE_WCSLEN = 1, - .HAVE_WCSNLEN = 1, - .HAVE_WEAK_SYMBOLS = null, - .HAVE_WINDOWS_LOCALE_T = null, - .HAVE_WINT_T = 1, - .HAVE_WORKING_O_NOATIME = 1, - .HAVE_WORKING_O_NOFOLLOW = 1, - .HAVE_WORKING_SWPRINTF = null, - .HAVE_WORKING_USELOCALE = 1, - .HAVE_WPRINTF = 1, - .HAVE_XLOCALE_H = 1, - .HAVE___FSETLOCKING = null, - .HAVE___HEADER_INLINE = 1, - .ICONV_CONST = {}, - .LDBL_EXPBIT0_BIT = 20, - .LDBL_EXPBIT0_WORD = 1, - .LDBL_SIGNBIT_BIT = null, - .LDBL_SIGNBIT_WORD = null, - .LOCALENAME_ENHANCE_LOCALE_FUNCS = null, - .LT_OBJDIR = ".libs/", - .MAP_ANONYMOUS = null, - .MBRTOWC_EMPTY_INPUT_BUG = null, - .MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ = null, - .MBRTOWC_NULL_ARG1_BUG = null, - .MBRTOWC_NULL_ARG2_BUG = null, - .MBRTOWC_NUL_RETVAL_BUG = null, - .MBRTOWC_RETVAL_BUG = null, - .MBRTOWC_STORES_INCOMPLETE_BUG = null, - .__USE_MINGW_ANSI_STDIO = 1, - .MUSL_LIBC = null, - .NEED_PRINTF_DIRECTIVE_A = 1, - .NEED_PRINTF_DIRECTIVE_B = 1, - .NEED_PRINTF_DIRECTIVE_F = null, - .NEED_PRINTF_DIRECTIVE_LC = null, - .NEED_PRINTF_DIRECTIVE_LS = null, - .NEED_PRINTF_DOUBLE = 1, - .NEED_PRINTF_ENOMEM = 1, - .NEED_PRINTF_FLAG_ALT_PRECISION_ZERO = null, - .NEED_PRINTF_FLAG_GROUPING = null, - .NEED_PRINTF_FLAG_LEFTADJUST = null, - .NEED_PRINTF_FLAG_ZERO = null, - .NEED_PRINTF_INFINITE_DOUBLE = null, - .NEED_PRINTF_INFINITE_LONG_DOUBLE = null, - .NEED_PRINTF_LONG_DOUBLE = 1, - .NEED_PRINTF_UNBOUNDED_PRECISION = null, - .NEED_WPRINTF_DIRECTIVE_C = 1, - .NEED_WPRINTF_DIRECTIVE_LA = null, - .NEED_WPRINTF_DIRECTIVE_LC = 1, - .PACKAGE = "libintl", - .PACKAGE_BUGREPORT = "bug-gettext@gnu.org", - .PACKAGE_NAME = "libintl", - .PACKAGE_STRING = "libintl 0.24", - .PACKAGE_TARNAME = "libintl", - .PACKAGE_URL = "", - .PACKAGE_VERSION = "0.24", - .PTHREAD_IN_USE_DETECTION_HARD = null, - .PTRDIFF_T_SUFFIX = null, - .REPLACE_VASNPRINTF = null, - .SETLOCALE_NULL_ALL_MTSAFE = 0, - .SETLOCALE_NULL_ONE_MTSAFE = 1, - .SIG_ATOMIC_T_SUFFIX = null, - .SIZE_MAX = null, - .SIZE_T_SUFFIX = null, - .STACK_DIRECTION = null, - .STDC_HEADERS = 1, - .USE_ISOC_AND_POSIX_THREADS = null, - .USE_ISOC_THREADS = null, - .USE_POSIX_THREADS = 1, - .USE_POSIX_THREADS_FROM_LIBC = null, - .USE_POSIX_THREADS_WEAK = null, - ._ALL_SOURCE = 1, - ._DARWIN_C_SOURCE = 1, - .__EXTENSIONS__ = 1, - ._GNU_SOURCE = 1, - ._HPUX_ALT_XOPEN_SOCKET_API = 1, - ._MINIX = null, - ._NETBSD_SOURCE = 1, - ._OPENBSD_SOURCE = 1, - ._POSIX_SOURCE = null, - ._POSIX_1_SOURCE = null, - ._POSIX_PTHREAD_SEMANTICS = 1, - .__STDC_WANT_IEC_60559_ATTRIBS_EXT__ = 1, - .__STDC_WANT_IEC_60559_BFP_EXT__ = 1, - .__STDC_WANT_IEC_60559_DFP_EXT__ = 1, - .__STDC_WANT_IEC_60559_EXT__ = 1, - .__STDC_WANT_IEC_60559_FUNCS_EXT__ = 1, - .__STDC_WANT_IEC_60559_TYPES_EXT__ = 1, - .__STDC_WANT_LIB_EXT2__ = 1, - .__STDC_WANT_MATH_SPEC_FUNCS__ = 1, - ._TANDEM_SOURCE = 1, - ._XOPEN_SOURCE = null, - .USE_WINDOWS_THREADS = null, - .VERSION = "0.24", - .WCHAR_T_SUFFIX = null, - .WINT_T_SUFFIX = null, - .WORDS_BIGENDIAN = null, - ._ISOC11_SOURCE = null, - ._LCONV_C99 = null, - ._LINUX_SOURCE_COMPAT = 1, - ._USE_STD_STAT = 1, - .__STDC_CONSTANT_MACROS = null, - .__STDC_LIMIT_MACROS = null, - .frexp = null, - .frexpl = null, - .@"inline" = null, - .intmax_t = null, - .mbrtowc = null, - .mbsinit = null, - .mbstate_t = null, - .memchr = null, - .mode_t = null, - .pid_t = null, - .ptrdiff_t = null, - .restrict = null, - //.restrict = "__restrict__", - .rpl_fgetc = null, - .rpl_fgets = null, - .rpl_fprintf = null, - .rpl_fputc = null, - .rpl_fputs = null, - .rpl_fread = null, - .rpl_frexp = null, - .rpl_frexpl = null, - .rpl_fscanf = null, - .rpl_fwrite = null, - .rpl_mbrtowc = null, - .rpl_mbsinit = null, - .rpl_memchr = null, - .rpl_tdelete = null, - .rpl_tfind = null, - .rpl_tsearch = null, - .rpl_twalk = null, - .rpl_vfprintf = null, - .size_t = null, - .ssize_t = null, - .tdelete = null, - .tfind = null, - .tsearch = null, - .twalk = null, - }, - ); - var flags = std.ArrayList([]const u8).init(b.allocator); defer flags.deinit(); try flags.appendSlice(&.{ @@ -365,7 +47,6 @@ pub fn build(b: *std.Build) !void { try apple_sdk.addPaths(b, &lib.root_module); } - lib.addConfigHeader(config); lib.addCSourceFiles(.{ .root = upstream.path("gettext-runtime/intl"), .files = srcs, @@ -402,6 +83,16 @@ const srcs: []const []const u8 = &.{ "version.c", "compat.c", + // There's probably a better way to detect that we need these, but + // these are hardcoded for now for macOS. + "gnulib-lib/getlocalename_l-unsafe.c", + "gnulib-lib/localename.c", + "gnulib-lib/localename-environ.c", + "gnulib-lib/localename-unsafe.c", + "gnulib-lib/setlocale-lock.c", + "gnulib-lib/setlocale_null.c", + "gnulib-lib/setlocale_null-unlocked.c", + // Not needed for macOS, but we might need them for other platforms. // If we expand this to support other platforms, we should uncomment // these. diff --git a/pkg/libintl/config.h b/pkg/libintl/config.h new file mode 100644 index 000000000..93d4e0246 --- /dev/null +++ b/pkg/libintl/config.h @@ -0,0 +1,2370 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Witness that has been included. */ +#define _GL_CONFIG_H_INCLUDED 1 + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* Define if no multithread safety and no multithreading is desired. */ +/* #undef AVOID_ANY_THREADS */ + +/* Define to the number of bits in type 'ptrdiff_t'. */ +/* #undef BITSIZEOF_PTRDIFF_T */ + +/* Define to the number of bits in type 'sig_atomic_t'. */ +/* #undef BITSIZEOF_SIG_ATOMIC_T */ + +/* Define to the number of bits in type 'size_t'. */ +/* #undef BITSIZEOF_SIZE_T */ + +/* Define to the number of bits in type 'wchar_t'. */ +/* #undef BITSIZEOF_WCHAR_T */ + +/* Define to the number of bits in type 'wint_t'. */ +/* #undef BITSIZEOF_WINT_T */ + +/* Define if you wish *printf() functions that have a safe handling of + non-IEEE-754 'long double' values. */ +#define CHECK_PRINTF_SAFE 1 + +/* Define to 1 if using 'alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define as the bit index in the word where to find bit 0 of the exponent of + 'double'. */ +#define DBL_EXPBIT0_BIT 20 + +/* Define as the word index where to find the exponent of 'double'. */ +#define DBL_EXPBIT0_WORD 1 + +/* Define as the bit index in the word where to find the sign of 'double'. */ +/* #undef DBL_SIGNBIT_BIT */ + +/* Define as the word index where to find the sign of 'double'. */ +/* #undef DBL_SIGNBIT_WORD */ + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#define ENABLE_NLS 1 + +/* Define to nothing if C supports flexible array members, and to 1 if it does + not. That way, with a declaration like 'struct s { int n; short + d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99 + compilers. Use 'FLEXSIZEOF (struct s, d, N * sizeof (short))' to calculate + the size in bytes of such a struct containing an N-element array. */ +#define FLEXIBLE_ARRAY_MEMBER /**/ + +/* Define as the bit index in the word where to find bit 0 of the exponent of + 'float'. */ +#define FLT_EXPBIT0_BIT 23 + +/* Define as the word index where to find the exponent of 'float'. */ +#define FLT_EXPBIT0_WORD 0 + +/* Define as the bit index in the word where to find the sign of 'float'. */ +/* #undef FLT_SIGNBIT_BIT */ + +/* Define as the word index where to find the sign of 'float'. */ +/* #undef FLT_SIGNBIT_WORD */ + +/* Define to a C preprocessor expression that evaluates to 1 or 0, depending + whether the gnulib module fscanf shall be considered present. */ +#define GNULIB_FSCANF 1 + +/* Define to a C preprocessor expression that evaluates to 1 or 0, depending + whether the gnulib module lock shall be considered present. */ +#define GNULIB_LOCK 1 + +/* Define to 1 if printf and friends should be labeled with attribute + "__gnu_printf__" instead of "__printf__" */ +/* #undef GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU */ + +/* Define to a C preprocessor expression that evaluates to 1 or 0, depending + whether the gnulib module scanf shall be considered present. */ +#define GNULIB_SCANF 1 + +/* Define to 1 when the gnulib module fgetc should be tested. */ +#define GNULIB_TEST_FGETC 1 + +/* Define to 1 when the gnulib module fgets should be tested. */ +#define GNULIB_TEST_FGETS 1 + +/* Define to 1 when the gnulib module fprintf should be tested. */ +#define GNULIB_TEST_FPRINTF 1 + +/* Define to 1 when the gnulib module fputc should be tested. */ +#define GNULIB_TEST_FPUTC 1 + +/* Define to 1 when the gnulib module fputs should be tested. */ +#define GNULIB_TEST_FPUTS 1 + +/* Define to 1 when the gnulib module fread should be tested. */ +#define GNULIB_TEST_FREAD 1 + +/* Define to 1 when the gnulib module free-posix should be tested. */ +#define GNULIB_TEST_FREE_POSIX 1 + +/* Define to 1 when the gnulib module frexp should be tested. */ +#define GNULIB_TEST_FREXP 1 + +/* Define to 1 when the gnulib module frexpl should be tested. */ +#define GNULIB_TEST_FREXPL 1 + +/* Define to 1 when the gnulib module fscanf should be tested. */ +#define GNULIB_TEST_FSCANF 1 + +/* Define to 1 when the gnulib module fwrite should be tested. */ +#define GNULIB_TEST_FWRITE 1 + +/* Define to 1 when the gnulib module getc should be tested. */ +#define GNULIB_TEST_GETC 1 + +/* Define to 1 when the gnulib module getchar should be tested. */ +#define GNULIB_TEST_GETCHAR 1 + +/* Define to 1 when the gnulib module getcwd should be tested. */ +#define GNULIB_TEST_GETCWD 1 + +/* Define to 1 when the gnulib module getlocalename_l-unsafe should be tested. + */ +#define GNULIB_TEST_GETLOCALENAME_L_UNSAFE 1 + +/* Define to 1 when the gnulib module localename-environ should be tested. */ +#define GNULIB_TEST_LOCALENAME_ENVIRON 1 + +/* Define to 1 when the gnulib module localename-unsafe should be tested. */ +#define GNULIB_TEST_LOCALENAME_UNSAFE 1 + +/* Define to 1 when the gnulib module mbrtowc should be tested. */ +#define GNULIB_TEST_MBRTOWC 1 + +/* Define to 1 when the gnulib module mbsinit should be tested. */ +#define GNULIB_TEST_MBSINIT 1 + +/* Define to 1 when the gnulib module mbszero should be tested. */ +#define GNULIB_TEST_MBSZERO 1 + +/* Define to 1 when the gnulib module memchr should be tested. */ +#define GNULIB_TEST_MEMCHR 1 + +/* Define to 1 when the gnulib module printf should be tested. */ +#define GNULIB_TEST_PRINTF 1 + +/* Define to 1 when the gnulib module pthread-once should be tested. */ +#define GNULIB_TEST_PTHREAD_ONCE 1 + +/* Define to 1 when the gnulib module putc should be tested. */ +#define GNULIB_TEST_PUTC 1 + +/* Define to 1 when the gnulib module putchar should be tested. */ +#define GNULIB_TEST_PUTCHAR 1 + +/* Define to 1 when the gnulib module puts should be tested. */ +#define GNULIB_TEST_PUTS 1 + +/* Define to 1 when the gnulib module scanf should be tested. */ +#define GNULIB_TEST_SCANF 1 + +/* Define to 1 when the gnulib module setlocale_null should be tested. */ +#define GNULIB_TEST_SETLOCALE_NULL 1 + +/* Define to 1 when the gnulib module signbit should be tested. */ +#define GNULIB_TEST_SIGNBIT 1 + +/* Define to 1 when the gnulib module tsearch should be tested. */ +#define GNULIB_TEST_TSEARCH 1 + +/* Define to 1 when the gnulib module vfprintf should be tested. */ +#define GNULIB_TEST_VFPRINTF 1 + +/* Define to 1 when the gnulib module vprintf should be tested. */ +#define GNULIB_TEST_VPRINTF 1 + +/* Define to 1 when the gnulib module wgetcwd should be tested. */ +#define GNULIB_TEST_WGETCWD 1 + +/* Define to 1 when the gnulib module wmemcpy should be tested. */ +#define GNULIB_TEST_WMEMCPY 1 + +/* Define to 1 when the gnulib module wmemset should be tested. */ +#define GNULIB_TEST_WMEMSET 1 + +/* Define if the __locale_t type contains the name of the LC_MESSAGES + category. */ +/* #undef HAVE_AIX72_LOCALES */ + +/* Define to 1 if you have 'alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if works. */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the 'asprintf' function. */ +#define HAVE_ASPRINTF 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BP_SYM_H */ + +/* Define to 1 if the compiler understands __builtin_expect. */ +#define HAVE_BUILTIN_EXPECT 1 + +/* Define to 1 if you have the Mac OS X function + CFLocaleCopyPreferredLanguages in the CoreFoundation framework. */ +#define HAVE_CFLOCALECOPYPREFERREDLANGUAGES 1 + +/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in + the CoreFoundation framework. */ +#define HAVE_CFPREFERENCESCOPYAPPVALUE 1 + +/* Define if the copysignf function is declared in and available in + libc. */ +/* #undef HAVE_COPYSIGNF_IN_LIBC */ + +/* Define if the copysignl function is declared in and available in + libc. */ +/* #undef HAVE_COPYSIGNL_IN_LIBC */ + +/* Define if the copysign function is declared in and available in + libc. */ +/* #undef HAVE_COPYSIGN_IN_LIBC */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CRTDEFS_H */ + +/* Define to 1 if bool, true and false work as per C2023. */ +/* #undef HAVE_C_BOOL */ + +/* Define to 1 if the static_assert keyword works. */ +/* #undef HAVE_C_STATIC_ASSERT */ + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +/* #undef HAVE_DCGETTEXT */ + +/* Define to 1 if you have the declaration of 'alarm', and to 0 if you don't. + */ +#define HAVE_DECL_ALARM 1 + +/* Define to 1 if you have the declaration of 'copysign', and to 0 if you + don't. */ +/* #undef HAVE_DECL_COPYSIGN */ + +/* Define to 1 if you have the declaration of 'copysignf', and to 0 if you + don't. */ +/* #undef HAVE_DECL_COPYSIGNF */ + +/* Define to 1 if you have the declaration of 'copysignl', and to 0 if you + don't. */ +/* #undef HAVE_DECL_COPYSIGNL */ + +/* Define to 1 if you have the declaration of 'ecvt', and to 0 if you don't. + */ +#define HAVE_DECL_ECVT 1 + +/* Define to 1 if you have the declaration of 'execvpe', and to 0 if you + don't. */ +#define HAVE_DECL_EXECVPE 0 + +/* Define to 1 if you have the declaration of 'fcloseall', and to 0 if you + don't. */ +#define HAVE_DECL_FCLOSEALL 0 + +/* Define to 1 if you have the declaration of 'fcvt', and to 0 if you don't. + */ +#define HAVE_DECL_FCVT 1 + +/* Define to 1 if you have the declaration of 'feof_unlocked', and to 0 if you + don't. */ +#define HAVE_DECL_FEOF_UNLOCKED 1 + +/* Define to 1 if you have the declaration of 'fgets_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_FGETS_UNLOCKED 0 + +/* Define to 1 if you have the declaration of 'gcvt', and to 0 if you don't. + */ +#define HAVE_DECL_GCVT 1 + +/* Define to 1 if you have the declaration of 'getw', and to 0 if you don't. + */ +#define HAVE_DECL_GETW 1 + +/* Define to 1 if you have the declaration of 'mbrtowc', and to 0 if you + don't. */ +/* #undef HAVE_DECL_MBRTOWC */ + +/* Define to 1 if you have the declaration of 'mbsinit', and to 0 if you + don't. */ +/* #undef HAVE_DECL_MBSINIT */ + +/* Define to 1 if you have the declaration of 'putw', and to 0 if you don't. + */ +#define HAVE_DECL_PUTW 1 + +/* Define to 1 if you have the declaration of 'wcsdup', and to 0 if you don't. + */ +#define HAVE_DECL_WCSDUP 1 + +/* Define to 1 if you have the declaration of 'wcsnlen', and to 0 if you + don't. */ +#define HAVE_DECL_WCSNLEN 1 + +/* Define to 1 if you have the declaration of '_snprintf', and to 0 if you + don't. */ +#define HAVE_DECL__SNPRINTF 0 + +/* Define to 1 if you have the declaration of '_snwprintf', and to 0 if you + don't. */ +#define HAVE_DECL__SNWPRINTF 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the `duplocale' function. */ +#define HAVE_DUPLOCALE 1 + +/* Define if the locale_t type contains insufficient information, as on + OpenBSD. */ +/* #undef HAVE_FAKE_LOCALES */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_FEATURES_H */ + +/* Define to 1 if you have the `freelocale' function. */ +#define HAVE_FREELOCALE 1 + +/* Define if the 'free' function is guaranteed to preserve errno. */ +/* #undef HAVE_FREE_POSIX */ + +/* Define if the frexpl function is available in libc. */ +#define HAVE_FREXPL_IN_LIBC 1 + +/* Define if the frexp function is available in libc. */ +#define HAVE_FREXP_IN_LIBC 1 + +/* Define to 1 if you have the 'getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the 'getegid' function. */ +#define HAVE_GETEGID 1 + +/* Define to 1 if you have the 'geteuid' function. */ +#define HAVE_GETEUID 1 + +/* Define to 1 if you have the 'getgid' function. */ +#define HAVE_GETGID 1 + +/* Define to 1 if you have the 'getlocalename_l' function. */ +/* #undef HAVE_GETLOCALENAME_L */ + +/* Define to 1 if you have the 'getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define if the GNU gettext() function is already present or preinstalled. */ +/* #undef HAVE_GETTEXT */ + +/* Define to 1 if you have the 'getuid' function. */ +#define HAVE_GETUID 1 + +/* Define if the uselocale function exists, may be safely called, and returns + sufficient information. */ +#define HAVE_GOOD_USELOCALE 1 + +/* Define if you have the iconv() function and it works. */ +/* #undef HAVE_ICONV */ + +/* Define if you have the 'intmax_t' type in or . */ +#define HAVE_INTMAX_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define if exists, doesn't clash with , and + declares uintmax_t. */ +#define HAVE_INTTYPES_H_WITH_UINTMAX 1 + +/* Define if the isnan(double) function is available in libc. */ +#define HAVE_ISNAND_IN_LIBC 1 + +/* Define if the isnan(float) function is available in libc. */ +#define HAVE_ISNANF_IN_LIBC 1 + +/* Define if the isnan(long double) function is available in libc. */ +#define HAVE_ISNANL_IN_LIBC 1 + +/* Define if you have and nl_langinfo(CODESET). */ +#define HAVE_LANGINFO_CODESET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LANGINFO_H 1 + +/* Define if your file defines LC_MESSAGES. */ +#define HAVE_LC_MESSAGES 1 + +/* Define if the ldexpl function is available in libc. */ +#define HAVE_LDEXPL_IN_LIBC 1 + +/* Define if the ldexp function is available in libc. */ +#define HAVE_LDEXP_IN_LIBC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if the system has the type 'long long int'. */ +#define HAVE_LONG_LONG_INT 1 + +/* Define to 1 if mmap()'s MAP_ANONYMOUS flag is available after including + config.h and . */ +#define HAVE_MAP_ANONYMOUS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MATH_H 1 + +/* Define to 1 if you have the 'mbrtowc' function. */ +#define HAVE_MBRTOWC 1 + +/* Define to 1 if you have the 'mbsinit' function. */ +#define HAVE_MBSINIT 1 + +/* Define to 1 if declares mbstate_t. */ +#define HAVE_MBSTATE_T 1 + +/* Define to 1 if you have the 'mempcpy' function. */ +/* #undef HAVE_MEMPCPY */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MINIX_CONFIG_H */ + +/* Define to 1 if you have a working 'mmap' system call. */ +#define HAVE_MMAP 1 + +/* Define to 1 if you have the 'mprotect' function. */ +#define HAVE_MPROTECT 1 + +/* Define to 1 if you have the 'munmap' function. */ +#define HAVE_MUNMAP 1 + +/* Define if the locale_t type does not contain the name of each locale + category. */ +/* #undef HAVE_NAMELESS_LOCALES */ + +/* Define to 1 if you have the 'newlocale' function. */ +#define HAVE_NEWLOCALE 1 + +/* Define to 1 if you have the `nl_langinfo' function. */ +#define HAVE_NL_LANGINFO 1 + +/* Define if your printf() function supports format strings with positions. */ +#define HAVE_POSIX_PRINTF 1 + +/* Define if you have the header and the POSIX threads API. */ +#define HAVE_PTHREAD_API 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PTHREAD_H 1 + +/* Define if the defines PTHREAD_MUTEX_RECURSIVE. */ +#define HAVE_PTHREAD_MUTEX_RECURSIVE 1 + +/* Define if the POSIX multithreading library has read/write locks. */ +#define HAVE_PTHREAD_RWLOCK 1 + +/* Define if the 'pthread_rwlock_rdlock' function prefers a writer to a + reader. */ +#define HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER 1 + +/* Define to 1 if the system has the type 'pthread_spinlock_t'. */ +/* #undef HAVE_PTHREAD_SPINLOCK_T */ + +/* Define to 1 if the system has the type 'pthread_t'. */ +#define HAVE_PTHREAD_T 1 + +/* Define to 1 if 'long double' and 'double' have the same representation. */ +#define HAVE_SAME_LONG_DOUBLE_AS_DOUBLE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SCHED_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SEARCH_H 1 + +/* Define to 1 if 'sig_atomic_t' is a signed integer type. */ +/* #undef HAVE_SIGNED_SIG_ATOMIC_T */ + +/* Define to 1 if 'wchar_t' is a signed integer type. */ +/* #undef HAVE_SIGNED_WCHAR_T */ + +/* Define to 1 if 'wint_t' is a signed integer type. */ +/* #undef HAVE_SIGNED_WINT_T */ + +/* Define to 1 if you have the 'snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define if the return value of the snprintf function is the number of of + bytes (excluding the terminating NUL) that would have been produced if the + buffer had been large enough. */ +#define HAVE_SNPRINTF_RETVAL_C99 1 + +/* Define if the string produced by the snprintf function is always NUL + terminated. */ +#define HAVE_SNPRINTF_TRUNCATION_C99 1 + +/* Define if the locale_t type is as on Solaris 11.4. */ +/* #undef HAVE_SOLARIS114_LOCALES */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define if exists, doesn't clash with , and declares + uintmax_t. */ +#define HAVE_STDINT_H_WITH_UINTMAX 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the 'stpcpy' function. */ +#define HAVE_STPCPY 1 + +/* Define to 1 if you have the 'strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the 'strnlen' function. */ +#define HAVE_STRNLEN 1 + +/* Define to 1 if you have the 'swprintf' function. */ +#define HAVE_SWPRINTF 1 + +/* Define to 1 if you have the 'symlink' function. */ +#define HAVE_SYMLINK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BITYPES_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_INTTYPES_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SINGLE_THREADED_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the `thrd_create' function. */ +/* #undef HAVE_THRD_CREATE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_THREADS_H */ + +/* Define to 1 if you have the `tsearch' function. */ +#define HAVE_TSEARCH 1 + +/* Define to 1 if you have the `twalk' function. */ +#define HAVE_TWALK 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if the system has the type 'unsigned long long int'. */ +#define HAVE_UNSIGNED_LONG_LONG_INT 1 + +/* Define to 1 if you have the 'uselocale' function. */ +#define HAVE_USELOCALE 1 + +/* Define to 1 if you have the 'vasnprintf' function. */ +/* #undef HAVE_VASNPRINTF */ + +/* Define to 1 or 0, depending whether the compiler supports simple visibility + declarations. */ +#define HAVE_VISIBILITY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if you have the 'wcrtomb' function. */ +#define HAVE_WCRTOMB 1 + +/* Define to 1 if you have the 'wcslen' function. */ +#define HAVE_WCSLEN 1 + +/* Define to 1 if you have the 'wcsnlen' function. */ +#define HAVE_WCSNLEN 1 + +/* Define to 1 if the compiler and linker support weak declarations of + symbols. */ +/* #undef HAVE_WEAK_SYMBOLS */ + +/* Define to 1 if defines the _locale_t type. */ +/* #undef HAVE_WINDOWS_LOCALE_T */ + +/* Define if you have the 'wint_t' type. */ +#define HAVE_WINT_T 1 + +/* Define to 1 if O_NOATIME works. */ +#define HAVE_WORKING_O_NOATIME 1 + +/* Define to 1 if O_NOFOLLOW works. */ +#define HAVE_WORKING_O_NOFOLLOW 1 + +/* Define if the swprintf function works correctly when it produces output + that contains null wide characters. */ +/* #undef HAVE_WORKING_SWPRINTF */ + +/* Define if the uselocale function exists and may safely be called. */ +#define HAVE_WORKING_USELOCALE 1 + +/* Define to 1 if you have the 'wprintf' function. */ +#define HAVE_WPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_XLOCALE_H 1 + +/* Define to 1 if you have the '__fsetlocking' function. */ +/* #undef HAVE___FSETLOCKING */ + +/* Define to 1 if ctype.h defines __header_inline. */ +#define HAVE___HEADER_INLINE 1 + +/* Please see the Gnulib manual for how to use these macros. + + Suppress extern inline with HP-UX cc, as it appears to be broken; see + . + + Suppress extern inline with Sun C in standards-conformance mode, as it + mishandles inline functions that call each other. E.g., for 'inline void f + (void) { } inline void g (void) { f (); }', c99 incorrectly complains + 'reference to static identifier "f" in extern inline function'. + This bug was observed with Oracle Developer Studio 12.6 + (Sun C 5.15 SunOS_sparc 2017/05/30). + + Suppress extern inline (with or without __attribute__ ((__gnu_inline__))) + on configurations that mistakenly use 'static inline' to implement + functions or macros in standard C headers like . For example, + if isdigit is mistakenly implemented via a static inline function, + a program containing an extern inline function that calls isdigit + may not work since the C standard prohibits extern inline functions + from calling static functions (ISO C 99 section 6.7.4.(3). + This bug is known to occur on: + + OS X 10.8 and earlier; see: + https://lists.gnu.org/r/bug-gnulib/2012-12/msg00023.html + + DragonFly; see + http://muscles.dragonflybsd.org/bulk/clang-master-potential/20141111_102002/logs/ah-tty-0.3.12.log + + FreeBSD; see: + https://lists.gnu.org/r/bug-gnulib/2014-07/msg00104.html + + OS X 10.9 has a macro __header_inline indicating the bug is fixed for C and + for clang but remains for g++; see . + Assume DragonFly and FreeBSD will be similar. + + GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 + inline semantics, unless -fgnu89-inline is used. It defines a macro + __GNUC_STDC_INLINE__ to indicate this situation or a macro + __GNUC_GNU_INLINE__ to indicate the opposite situation. + GCC 4.2 with -std=c99 or -std=gnu99 implements the GNU C inline + semantics but warns, unless -fgnu89-inline is used: + warning: C99 inline functions are not supported; using GNU89 + warning: to disable this warning use -fgnu89-inline or the gnu_inline + function attribute It defines a macro __GNUC_GNU_INLINE__ to indicate this + situation. + */ +#if (((defined __APPLE__ && defined __MACH__) || defined __DragonFly__ || \ + defined __FreeBSD__) && \ + (defined HAVE___HEADER_INLINE \ + ? (defined __cplusplus && defined __GNUC_STDC_INLINE__ && \ + !defined __clang__) \ + : ((!defined _DONT_USE_CTYPE_INLINE_ && \ + (defined __GNUC__ || defined __cplusplus)) || \ + (defined _FORTIFY_SOURCE && 0 < _FORTIFY_SOURCE && \ + defined __GNUC__ && !defined __cplusplus)))) +#define _GL_EXTERN_INLINE_STDHEADER_BUG +#endif +#if ((__GNUC__ ? (defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ && \ + !defined __PCC__) \ + : (199901L <= __STDC_VERSION__ && !defined __HP_cc && \ + !defined __PGI && !(defined __SUNPRO_C && __STDC__))) && \ + !defined _GL_EXTERN_INLINE_STDHEADER_BUG) +#define _GL_INLINE inline +#define _GL_EXTERN_INLINE extern inline +#define _GL_EXTERN_INLINE_IN_USE +#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ && \ + !defined __PCC__ && !defined _GL_EXTERN_INLINE_STDHEADER_BUG) +#if defined __GNUC_GNU_INLINE__ && __GNUC_GNU_INLINE__ +/* __gnu_inline__ suppresses a GCC 4.2 diagnostic. */ +#define _GL_INLINE extern inline __attribute__((__gnu_inline__)) +#else +#define _GL_INLINE extern inline +#endif +#define _GL_EXTERN_INLINE extern +#define _GL_EXTERN_INLINE_IN_USE +#else +#define _GL_INLINE _GL_UNUSED static +#define _GL_EXTERN_INLINE _GL_UNUSED static +#endif + +/* In GCC 4.6 (inclusive) to 5.1 (exclusive), + suppress bogus "no previous prototype for 'FOO'" + and "no previous declaration for 'FOO'" diagnostics, + when FOO is an inline function in the header; see + and + . */ +#if __GNUC__ == 4 && 6 <= __GNUC_MINOR__ +#if defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ +#define _GL_INLINE_HEADER_CONST_PRAGMA +#else +#define _GL_INLINE_HEADER_CONST_PRAGMA \ + _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=const\"") +#endif +#define _GL_INLINE_HEADER_BEGIN \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"") \ + _Pragma("GCC diagnostic ignored \"-Wmissing-declarations\"") \ + _GL_INLINE_HEADER_CONST_PRAGMA +#define _GL_INLINE_HEADER_END _Pragma("GCC diagnostic pop") +#else +#define _GL_INLINE_HEADER_BEGIN +#define _GL_INLINE_HEADER_END +#endif + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Define as the bit index in the word where to find bit 0 of the exponent of + 'long double'. */ +#define LDBL_EXPBIT0_BIT 20 + +/* Define as the word index where to find the exponent of 'long double'. */ +#define LDBL_EXPBIT0_WORD 1 + +/* Define as the bit index in the word where to find the sign of 'long + double'. */ +/* #undef LDBL_SIGNBIT_BIT */ + +/* Define as the word index where to find the sign of 'long double'. */ +/* #undef LDBL_SIGNBIT_WORD */ + +/* Define if localename.c overrides newlocale(), duplocale(), freelocale(). */ +/* #undef LOCALENAME_ENHANCE_LOCALE_FUNCS */ + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Define to a substitute value for mmap()'s MAP_ANONYMOUS flag. */ +/* #undef MAP_ANONYMOUS */ + +/* Define if the mbrtowc function does not return (size_t) -2 for empty input. + */ +/* #undef MBRTOWC_EMPTY_INPUT_BUG */ + +/* Define if the mbrtowc function may signal encoding errors in the C locale. + */ +/* #undef MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ */ + +/* Define if the mbrtowc function has the NULL pwc argument bug. */ +/* #undef MBRTOWC_NULL_ARG1_BUG */ + +/* Define if the mbrtowc function has the NULL string argument bug. */ +/* #undef MBRTOWC_NULL_ARG2_BUG */ + +/* Define if the mbrtowc function does not return 0 for a NUL character. */ +/* #undef MBRTOWC_NUL_RETVAL_BUG */ + +/* Define if the mbrtowc function returns a wrong return value. */ +/* #undef MBRTOWC_RETVAL_BUG */ + +/* Define if the mbrtowc function stores a wide character when reporting + incomplete input. */ +/* #undef MBRTOWC_STORES_INCOMPLETE_BUG */ + +/* Use GNU style printf and scanf. */ +#ifndef __USE_MINGW_ANSI_STDIO +#define __USE_MINGW_ANSI_STDIO 1 +#endif + +/* Define to 1 on musl libc. */ +/* #undef MUSL_LIBC */ + +/* Define if the vasnprintf implementation needs special code for the 'a' and + 'A' directives. */ +#define NEED_PRINTF_DIRECTIVE_A 1 + +/* Define if the vasnprintf implementation needs special code for the 'b' + directive. */ +#define NEED_PRINTF_DIRECTIVE_B 1 + +/* Define if the vasnprintf implementation needs special code for the 'F' + directive. */ +/* #undef NEED_PRINTF_DIRECTIVE_F */ + +/* Define if the vasnprintf implementation needs special code for the 'lc' + directive. */ +/* #undef NEED_PRINTF_DIRECTIVE_LC */ + +/* Define if the vasnprintf implementation needs special code for the 'ls' + directive. */ +/* #undef NEED_PRINTF_DIRECTIVE_LS */ + +/* Define if the vasnprintf implementation needs special code for 'double' + arguments. */ +#define NEED_PRINTF_DOUBLE 1 + +/* Define if the vasnprintf implementation needs special code for surviving + out-of-memory conditions. */ +#define NEED_PRINTF_ENOMEM 1 + +/* Define if the vasnprintf implementation needs special code for the # flag + with a zero precision and a zero value in the 'x' and 'X' directives. */ +/* #undef NEED_PRINTF_FLAG_ALT_PRECISION_ZERO */ + +/* Define if the vasnprintf implementation needs special code for the ' flag. + */ +/* #undef NEED_PRINTF_FLAG_GROUPING */ + +/* Define if the vasnprintf implementation needs special code for the '-' + flag. */ +/* #undef NEED_PRINTF_FLAG_LEFTADJUST */ + +/* Define if the vasnprintf implementation needs special code for the 0 flag. + */ +/* #undef NEED_PRINTF_FLAG_ZERO */ + +/* Define if the vasnprintf implementation needs special code for infinite + 'double' arguments. */ +/* #undef NEED_PRINTF_INFINITE_DOUBLE */ + +/* Define if the vasnprintf implementation needs special code for infinite + 'long double' arguments. */ +/* #undef NEED_PRINTF_INFINITE_LONG_DOUBLE */ + +/* Define if the vasnprintf implementation needs special code for 'long + double' arguments. */ +#define NEED_PRINTF_LONG_DOUBLE 1 + +/* Define if the vasnprintf implementation needs special code for supporting + large precisions without arbitrary bounds. */ +/* #undef NEED_PRINTF_UNBOUNDED_PRECISION */ + +/* Define if the vasnwprintf implementation needs special code for the 'c' + directive. */ +#define NEED_WPRINTF_DIRECTIVE_C 1 + +/* Define if the vasnwprintf implementation needs special code for the 'a' + directive with 'long double' arguments. */ +/* #undef NEED_WPRINTF_DIRECTIVE_LA */ + +/* Define if the vasnwprintf implementation needs special code for the 'lc' + directive. */ +#define NEED_WPRINTF_DIRECTIVE_LC 1 + +/* Name of package */ +#define PACKAGE "libintl" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-gettext@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libintl" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libintl 0.24" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libintl" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.24" + +/* Define if the pthread_in_use() detection is hard. */ +/* #undef PTHREAD_IN_USE_DETECTION_HARD */ + +/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type + 'ptrdiff_t'. */ +/* #undef PTRDIFF_T_SUFFIX */ + +/* Define if vasnprintf exists but is overridden by gnulib. */ +/* #undef REPLACE_VASNPRINTF */ + +/* Define to 1 if setlocale (LC_ALL, NULL) is multithread-safe. */ +#define SETLOCALE_NULL_ALL_MTSAFE 0 + +/* Define to 1 if setlocale (category, NULL) is multithread-safe. */ +#define SETLOCALE_NULL_ONE_MTSAFE 1 + +/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type + 'sig_atomic_t'. */ +/* #undef SIG_ATOMIC_T_SUFFIX */ + +/* Define as the maximum value of type 'size_t', if the system doesn't define + it. */ +#ifndef SIZE_MAX +/* # undef SIZE_MAX */ +#endif + +/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type + 'size_t'. */ +/* #undef SIZE_T_SUFFIX */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Define if the combination of the ISO C and POSIX multithreading APIs can be + used. */ +/* #undef USE_ISOC_AND_POSIX_THREADS */ + +/* Define if the ISO C multithreading library can be used. */ +/* #undef USE_ISOC_THREADS */ + +/* Define to enable the declarations of ISO C 23 Annex K types and functions. */ +#if !(defined __STDC_WANT_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__) +#undef /**/ __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 +#endif + +/* Define if the POSIX multithreading library can be used. */ +#define USE_POSIX_THREADS 1 + +/* Define if references to the POSIX multithreading library are satisfied by + libc. */ +/* #undef USE_POSIX_THREADS_FROM_LIBC */ + +/* Define if references to the POSIX multithreading library should be made + weak. */ +/* #undef USE_POSIX_THREADS_WEAK */ + +/* Enable extensions on AIX, Interix, z/OS. */ +#ifndef _ALL_SOURCE +#define _ALL_SOURCE 1 +#endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +#define _DARWIN_C_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +#define __EXTENSIONS__ 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +#define _HPUX_ALT_XOPEN_SOCKET_API 1 +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +/* # undef _MINIX */ +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +#define _NETBSD_SOURCE 1 +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +#define _OPENBSD_SOURCE 1 +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +/* # undef _POSIX_SOURCE */ +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +/* # undef _POSIX_1_SOURCE */ +#endif +/* Enable POSIX-compatible threading on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +#define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +#define __STDC_WANT_IEC_60559_BFP_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +#define __STDC_WANT_IEC_60559_DFP_EXT__ 1 +#endif +/* Enable extensions specified by C23 Annex F. */ +#ifndef __STDC_WANT_IEC_60559_EXT__ +#define __STDC_WANT_IEC_60559_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 +#endif +/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +#define __STDC_WANT_LIB_EXT2__ 1 +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +#define __STDC_WANT_MATH_SPEC_FUNCS__ 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +#define _TANDEM_SOURCE 1 +#endif +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +/* # undef _XOPEN_SOURCE */ +#endif + +/* Define if the native Windows multithreading API can be used. */ +/* #undef USE_WINDOWS_THREADS */ + +/* Version number of package */ +#define VERSION "0.24" + +/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type + 'wchar_t'. */ +/* #undef WCHAR_T_SUFFIX */ + +/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type + 'wint_t'. */ +/* #undef WINT_T_SUFFIX */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +#if defined __BIG_ENDIAN__ +#define WORDS_BIGENDIAN 1 +#endif +#else +#ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +#endif +#endif + +/* True if the compiler says it groks GNU C version MAJOR.MINOR. + Except that + - clang groks GNU C 4.2, even on Windows, where it does not define + __GNUC__. + - The OpenMandriva-modified clang compiler pretends that it groks + GNU C version 13.1, but it doesn't: It does not support + __attribute__ ((__malloc__ (f, i))), nor does it support + __attribute__ ((__warning__ (message))) on a function redeclaration. + - Users can make clang lie as well, through the -fgnuc-version option. */ +#if defined __GNUC__ && defined __GNUC_MINOR__ && !defined __clang__ +#define _GL_GNUC_PREREQ(major, minor) \ + ((major) < __GNUC__ + ((minor) <= __GNUC_MINOR__)) +#elif defined __clang__ +/* clang really only groks GNU C 4.2. */ +#define _GL_GNUC_PREREQ(major, minor) ((major) < 4 + ((minor) <= 2)) +#else +#define _GL_GNUC_PREREQ(major, minor) 0 +#endif + +/* Define to enable the declarations of ISO C 11 types and functions. */ +/* #undef _ISOC11_SOURCE */ + +/* Define to 1 on Solaris. */ +/* #undef _LCONV_C99 */ + +/* Define so that AIX headers are more compatible with GNU/Linux. */ +#define _LINUX_SOURCE_COMPAT 1 + +/* The _Noreturn keyword of C11. */ +#ifndef _Noreturn +#if (defined __cplusplus && \ + ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) || \ + (defined _MSC_VER && 1900 <= _MSC_VER)) && \ + 0) +/* [[noreturn]] is not practically usable, because with it the syntax + extern _Noreturn void func (...); + would not be valid; such a declaration would only be valid with 'extern' + and '_Noreturn' swapped, or without the 'extern' keyword. However, some + AIX system header files and several gnulib header files use precisely + this syntax with 'extern'. */ +#define _Noreturn [[noreturn]] +#elif (defined __clang__ && __clang_major__ < 16 && \ + defined _GL_WORK_AROUND_LLVM_BUG_59792) +/* Compile with -D_GL_WORK_AROUND_LLVM_BUG_59792 to work around + that rare LLVM bug, though you may get many false-alarm warnings. */ +#define _Noreturn +#elif ((!defined __cplusplus || defined __clang__) && \ + (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) || \ + (!defined __STRICT_ANSI__ && \ + (_GL_GNUC_PREREQ(4, 7) || \ + (defined __apple_build_version__ \ + ? 6000000 <= __apple_build_version__ \ + : 3 < __clang_major__ + (5 <= __clang_minor__)))))) +/* _Noreturn works as-is. */ +#elif _GL_GNUC_PREREQ(2, 8) || defined __clang__ || 0x5110 <= __SUNPRO_C +#define _Noreturn __attribute__((__noreturn__)) +#elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0) +#define _Noreturn __declspec(noreturn) +#else +#define _Noreturn +#endif +#endif + +/* For standard stat data types on VMS. */ +#define _USE_STD_STAT 1 + +/* Define to 1 if the system predates C++11. */ +/* #undef __STDC_CONSTANT_MACROS */ + +/* Define to 1 if the system predates C++11. */ +/* #undef __STDC_LIMIT_MACROS */ + +/* The _GL_ASYNC_SAFE marker should be attached to functions that are + signal handlers (for signals other than SIGABRT, SIGPIPE) or can be + invoked from such signal handlers. Such functions have some restrictions: + * All functions that it calls should be marked _GL_ASYNC_SAFE as well, + or should be listed as async-signal-safe in POSIX + + section 2.4.3. Note that malloc(), sprintf(), and fwrite(), in + particular, are NOT async-signal-safe. + * All memory locations (variables and struct fields) that these functions + access must be marked 'volatile'. This holds for both read and write + accesses. Otherwise the compiler might optimize away stores to and + reads from such locations that occur in the program, depending on its + data flow analysis. For example, when the program contains a loop + that is intended to inspect a variable set from within a signal handler + while (!signal_occurred) + ; + the compiler is allowed to transform this into an endless loop if the + variable 'signal_occurred' is not declared 'volatile'. + Additionally, recall that: + * A signal handler should not modify errno (except if it is a handler + for a fatal signal and ends by raising the same signal again, thus + provoking the termination of the process). If it invokes a function + that may clobber errno, it needs to save and restore the value of + errno. */ +#define _GL_ASYNC_SAFE + +/* Attributes. */ +/* Define _GL_HAS_ATTRIBUTE only once, because on FreeBSD, with gcc < 5, if + gets included once again after , __has_attribute(x) + expands to 0 always, and redefining _GL_HAS_ATTRIBUTE would turn off all + attributes. */ +#ifndef _GL_HAS_ATTRIBUTE +#if (defined __has_attribute && \ + (!defined __clang_minor__ || \ + (defined __apple_build_version__ ? 7000000 <= __apple_build_version__ \ + : 5 <= __clang_major__))) +#define _GL_HAS_ATTRIBUTE(attr) __has_attribute(__##attr##__) +#else +#define _GL_HAS_ATTRIBUTE(attr) _GL_ATTR_##attr +#define _GL_ATTR_alloc_size _GL_GNUC_PREREQ(4, 3) +#define _GL_ATTR_always_inline _GL_GNUC_PREREQ(3, 2) +#define _GL_ATTR_artificial _GL_GNUC_PREREQ(4, 3) +#define _GL_ATTR_cold _GL_GNUC_PREREQ(4, 3) +#define _GL_ATTR_const _GL_GNUC_PREREQ(2, 95) +#define _GL_ATTR_deprecated _GL_GNUC_PREREQ(3, 1) +#define _GL_ATTR_diagnose_if 0 +#define _GL_ATTR_error _GL_GNUC_PREREQ(4, 3) +#define _GL_ATTR_externally_visible _GL_GNUC_PREREQ(4, 1) +#define _GL_ATTR_fallthrough _GL_GNUC_PREREQ(7, 0) +#define _GL_ATTR_format _GL_GNUC_PREREQ(2, 7) +#define _GL_ATTR_leaf _GL_GNUC_PREREQ(4, 6) +#define _GL_ATTR_malloc _GL_GNUC_PREREQ(3, 0) +#ifdef _ICC +#define _GL_ATTR_may_alias 0 +#else +#define _GL_ATTR_may_alias _GL_GNUC_PREREQ(3, 3) +#endif +#define _GL_ATTR_noinline _GL_GNUC_PREREQ(3, 1) +#define _GL_ATTR_nonnull _GL_GNUC_PREREQ(3, 3) +#define _GL_ATTR_nonstring _GL_GNUC_PREREQ(8, 0) +#define _GL_ATTR_nothrow _GL_GNUC_PREREQ(3, 3) +#define _GL_ATTR_packed _GL_GNUC_PREREQ(2, 7) +#define _GL_ATTR_pure _GL_GNUC_PREREQ(2, 96) +#define _GL_ATTR_reproducible 0 /* not yet supported, as of GCC 14 */ +#define _GL_ATTR_returns_nonnull _GL_GNUC_PREREQ(4, 9) +#define _GL_ATTR_sentinel _GL_GNUC_PREREQ(4, 0) +#define _GL_ATTR_unsequenced 0 /* not yet supported, as of GCC 14 */ +#define _GL_ATTR_unused _GL_GNUC_PREREQ(2, 7) +#define _GL_ATTR_warn_unused_result _GL_GNUC_PREREQ(3, 4) +#endif +#endif + +/* Use __has_c_attribute if available. However, do not use with + pre-C23 GCC, which can issue false positives if -Wpedantic. */ +#if (defined __has_c_attribute && \ + !(_GL_GNUC_PREREQ(4, 6) && \ + (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) <= 201710)) +#define _GL_HAVE___HAS_C_ATTRIBUTE 1 +#else +#define _GL_HAVE___HAS_C_ATTRIBUTE 0 +#endif + +/* Attributes in bracket syntax [[...]] vs. attributes in __attribute__((...)) + syntax, in function declarations. There are two problems here. + (Last tested with gcc/g++ 14 and clang/clang++ 18.) + + 1) We want that the _GL_ATTRIBUTE_* can be cumulated on the same declaration + in any order. + =========================== foo.c = foo.cc =========================== + __attribute__ ((__deprecated__)) [[__nodiscard__]] int bar1 (int); + [[__nodiscard__]] __attribute__ ((__deprecated__)) int bar2 (int); + ====================================================================== + This gives a syntax error + - in C mode with gcc + , and + - in C++ mode with clang++ version < 16, and + - in C++ mode, inside extern "C" {}, still in newer clang++ versions + . + */ +/* Define if, in a function declaration, the attributes in bracket syntax + [[...]] must come before the attributes in __attribute__((...)) syntax. + If this is defined, it is best to avoid the bracket syntax, so that the + various _GL_ATTRIBUTE_* can be cumulated on the same declaration in any + order. */ +#ifdef __cplusplus +#if defined __clang__ +#define _GL_BRACKET_BEFORE_ATTRIBUTE 1 +#endif +#else +#if defined __GNUC__ && !defined __clang__ +#define _GL_BRACKET_BEFORE_ATTRIBUTE 1 +#endif +#endif +/* + 2) We want that the _GL_ATTRIBUTE_* can be placed in a declaration + - without 'extern', in C as well as in C++, + - with 'extern', in C, + - with 'extern "C"', in C++ + in the same position. That is, we don't want to be forced to use a + macro which arranges for the attribute to come before 'extern' in + one case and after 'extern' in the other case, because such a macro + would make the source code of .h files pretty ugly. + =========================== foo.c = foo.cc =========================== + #ifdef __cplusplus + # define CC "C" + #else + # define CC + #endif + + #define ND [[__nodiscard__]] + #define WUR __attribute__((__warn_unused_result__)) + + #ifdef __cplusplus + extern "C" { + #endif + // gcc clang g++ clang++ + + ND int foo (int); + int ND foo (int); // warn error warn error + int foo ND (int); + int foo (int) ND; // warn error warn error + + WUR int foo (int); + int WUR foo (int); + int fo1 WUR (int); // error error error error + int foo (int) WUR; + + #ifdef __cplusplus + } + #endif + + // gcc clang g++ clang++ + + ND extern CC int foo (int); // error error + extern CC ND int foo (int); // error error + extern CC int ND foo (int); // warn error warn error + extern CC int foo ND (int); + extern CC int foo (int) ND; // warn error warn error + + WUR extern CC int foo (int); // warn + extern CC WUR int foo (int); + extern CC int WUR foo (int); + extern CC int foo WUR (int); // error error error error + extern CC int foo (int) WUR; + + ND EXTERN_C_FUNC int foo (int); // error error + EXTERN_C_FUNC ND int foo (int); + EXTERN_C_FUNC int ND foo (int); // warn error warn error + EXTERN_C_FUNC int foo ND (int); + EXTERN_C_FUNC int foo (int) ND; // warn error warn error + + WUR EXTERN_C_FUNC int foo (int); // warn + EXTERN_C_FUNC WUR int foo (int); + EXTERN_C_FUNC int WUR foo (int); + EXTERN_C_FUNC int fo2 WUR (int); // error error error error + EXTERN_C_FUNC int foo (int) WUR; + ====================================================================== + So, if we insist on using the 'extern' keyword ('extern CC' idiom): + * If _GL_ATTRIBUTE_* expands to bracket syntax [[...]] + in both C and C++, there is one available position: + - between the function name and the parameter list. + * If _GL_ATTRIBUTE_* expands to __attribute__((...)) syntax + in both C and C++, there are several available positions: + - before the return type, + - between return type and function name, + - at the end of the declaration. + * If _GL_ATTRIBUTE_* expands to bracket syntax [[...]] in C and to + __attribute__((...)) syntax in C++, there is no available position: + it would need to come before 'extern' in C but after 'extern "C"' + in C++. + * If _GL_ATTRIBUTE_* expands to __attribute__((...)) syntax in C and + to bracket syntax [[...]] in C++, there is one available position: + - before the return type. + Whereas, if we use the 'EXTERN_C_FUNC' idiom, which conditionally + omits the 'extern' keyword: + * If _GL_ATTRIBUTE_* expands to bracket syntax [[...]] + in both C and C++, there are two available positions: + - before the return type, + - between the function name and the parameter list. + * If _GL_ATTRIBUTE_* expands to __attribute__((...)) syntax + in both C and C++, there are several available positions: + - before the return type, + - between return type and function name, + - at the end of the declaration. + * If _GL_ATTRIBUTE_* expands to bracket syntax [[...]] in C and to + __attribute__((...)) syntax in C++, there is one available position: + - before the return type. + * If _GL_ATTRIBUTE_* expands to __attribute__((...)) syntax in C and + to bracket syntax [[...]] in C++, there is one available position: + - before the return type. + The best choice is therefore to use the 'EXTERN_C_FUNC' idiom and + put the attributes before the return type. This works regardless + to what the _GL_ATTRIBUTE_* macros expand. + */ + +/* Attributes in bracket syntax [[...]] vs. attributes in __attribute__((...)) + syntax, in static/inline function definitions. + + There are similar constraints as for function declarations. However, here, + we cannot omit the storage-class specifier. Therefore, the following rule + applies: + * The macros + _GL_ATTRIBUTE_CONST + _GL_ATTRIBUTE_DEPRECATED + _GL_ATTRIBUTE_MAYBE_UNUSED + _GL_ATTRIBUTE_NODISCARD + _GL_ATTRIBUTE_PURE + _GL_ATTRIBUTE_REPRODUCIBLE + _GL_ATTRIBUTE_UNSEQUENCED + which may expand to bracket syntax [[...]], must come first, before the + storage-class specifier. + * Other _GL_ATTRIBUTE_* macros, that expand to __attribute__((...)) syntax, + are better placed between the storage-class specifier and the return + type. + */ + +/* Attributes in bracket syntax [[...]] vs. attributes in __attribute__((...)) + syntax, in variable declarations. + + At which position can they be placed? + (Last tested with gcc/g++ 14 and clang/clang++ 18.) + + =========================== foo.c = foo.cc =========================== + #ifdef __cplusplus + # define CC "C" + #else + # define CC + #endif + + #define BD [[__deprecated__]] + #define AD __attribute__ ((__deprecated__)) + + // gcc clang g++ clang++ + + BD extern CC int var; // error error + extern CC BD int var; // error error + extern CC int BD var; // warn error warn error + extern CC int var BD; + + AD extern CC int var; // warn + extern CC AD int var; + extern CC int AD var; + extern CC int var AD; + + BD extern CC int z[]; // error error + extern CC BD int z[]; // error error + extern CC int BD z[]; // warn error warn error + extern CC int z1 BD []; + extern CC int z[] BD; // warn error error + + AD extern CC int z[]; // warn + extern CC AD int z[]; + extern CC int AD z[]; + extern CC int z2 AD []; // error error error error + extern CC int z[] AD; + ====================================================================== + + * For non-array variables, the only good position is after the variable name, + that is, at the end of the declaration. + * For array variables, you will need to distinguish C and C++: + - In C, before the 'extern' keyword. + - In C++, between the 'extern "C"' and the variable's type. + */ + +/* _GL_ATTRIBUTE_ALLOC_SIZE ((N)) declares that the Nth argument of the function + is the size of the returned memory block. + _GL_ATTRIBUTE_ALLOC_SIZE ((M, N)) declares that the Mth argument multiplied + by the Nth argument of the function is the size of the returned memory block. + */ +/* Applies to: functions, pointer to functions, function types. */ +#ifndef _GL_ATTRIBUTE_ALLOC_SIZE +#if _GL_HAS_ATTRIBUTE(alloc_size) +#define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__((__alloc_size__ args)) +#else +#define _GL_ATTRIBUTE_ALLOC_SIZE(args) +#endif +#endif + +/* _GL_ATTRIBUTE_ALWAYS_INLINE tells that the compiler should always inline the + function and report an error if it cannot do so. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_ALWAYS_INLINE +#if _GL_HAS_ATTRIBUTE(always_inline) +#define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__((__always_inline__)) +#else +#define _GL_ATTRIBUTE_ALWAYS_INLINE +#endif +#endif + +/* _GL_ATTRIBUTE_ARTIFICIAL declares that the function is not important to show + in stack traces when debugging. The compiler should omit the function from + stack traces. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_ARTIFICIAL +#if _GL_HAS_ATTRIBUTE(artificial) +#define _GL_ATTRIBUTE_ARTIFICIAL __attribute__((__artificial__)) +#else +#define _GL_ATTRIBUTE_ARTIFICIAL +#endif +#endif + +/* _GL_ATTRIBUTE_COLD declares that the function is rarely executed. */ +/* Applies to: functions. */ +/* Avoid __attribute__ ((cold)) on MinGW; see thread starting at + . + Also, Oracle Studio 12.6 requires 'cold' not '__cold__'. */ +#ifndef _GL_ATTRIBUTE_COLD +#if _GL_HAS_ATTRIBUTE(cold) && !defined __MINGW32__ +#ifndef __SUNPRO_C +#define _GL_ATTRIBUTE_COLD __attribute__((__cold__)) +#else +#define _GL_ATTRIBUTE_COLD __attribute__((cold)) +#endif +#else +#define _GL_ATTRIBUTE_COLD +#endif +#endif + +/* _GL_ATTRIBUTE_CONST declares: + It is OK for a compiler to move calls to the function and to omit + calls to the function if another call has the same arguments or the + result is not used. + This attribute is safe for a function that neither depends on + nor affects state, and always returns exactly once - + e.g., does not raise an exception, call longjmp, or loop forever. + (This attribute is stricter than _GL_ATTRIBUTE_PURE because the + function cannot observe state. It is stricter than + _GL_ATTRIBUTE_UNSEQUENCED because the function must return exactly + once and cannot depend on state addressed by its arguments.) */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_CONST +#if _GL_HAS_ATTRIBUTE(const) +#define _GL_ATTRIBUTE_CONST __attribute__((__const__)) +#else +#define _GL_ATTRIBUTE_CONST _GL_ATTRIBUTE_UNSEQUENCED +#endif +#endif + +/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers + that can be freed by passing them as the Ith argument to the + function F. + _GL_ATTRIBUTE_DEALLOC_FREE declares that the function returns pointers that + can be freed via 'free'; it can be used only after declaring 'free'. */ +/* Applies to: functions. Cannot be used on inline functions. */ +#ifndef _GL_ATTRIBUTE_DEALLOC +#if _GL_GNUC_PREREQ(11, 0) +#define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__((__malloc__(f, i))) +#else +#define _GL_ATTRIBUTE_DEALLOC(f, i) +#endif +#endif +/* If gnulib's or has already defined this macro, continue + to use this earlier definition, since may not have been included + yet. */ +#ifndef _GL_ATTRIBUTE_DEALLOC_FREE +#if defined __cplusplus && defined __GNUC__ && !defined __clang__ +/* Work around GCC bug */ +#define _GL_ATTRIBUTE_DEALLOC_FREE \ + _GL_ATTRIBUTE_DEALLOC((void (*)(void*))free, 1) +#else +#define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC(free, 1) +#endif +#endif + +/* _GL_ATTRIBUTE_DEPRECATED: Declares that an entity is deprecated. + The compiler may warn if the entity is used. */ +/* Applies to: + - function, variable, + - struct, union, struct/union member, + - enumeration, enumeration item, + - typedef, + in C++ also: namespace, class, template specialization. */ +#ifndef _GL_ATTRIBUTE_DEPRECATED +#ifndef _GL_BRACKET_BEFORE_ATTRIBUTE +#if _GL_HAVE___HAS_C_ATTRIBUTE +#if __has_c_attribute(__deprecated__) +#define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]] +#endif +#endif +#endif +#if !defined _GL_ATTRIBUTE_DEPRECATED && _GL_HAS_ATTRIBUTE(deprecated) +#define _GL_ATTRIBUTE_DEPRECATED __attribute__((__deprecated__)) +#endif +#ifndef _GL_ATTRIBUTE_DEPRECATED +#define _GL_ATTRIBUTE_DEPRECATED +#endif +#endif + +/* _GL_ATTRIBUTE_ERROR(msg) requests an error if a function is called and + the function call is not optimized away. + _GL_ATTRIBUTE_WARNING(msg) requests a warning if a function is called and + the function call is not optimized away. */ +/* Applies to: functions. */ +#if !(defined _GL_ATTRIBUTE_ERROR && defined _GL_ATTRIBUTE_WARNING) +#if _GL_HAS_ATTRIBUTE(error) +#define _GL_ATTRIBUTE_ERROR(msg) __attribute__((__error__(msg))) +#define _GL_ATTRIBUTE_WARNING(msg) __attribute__((__warning__(msg))) +#elif _GL_HAS_ATTRIBUTE(diagnose_if) +#define _GL_ATTRIBUTE_ERROR(msg) \ + __attribute__((__diagnose_if__(1, msg, "error"))) +#define _GL_ATTRIBUTE_WARNING(msg) \ + __attribute__((__diagnose_if__(1, msg, "warning"))) +#else +#define _GL_ATTRIBUTE_ERROR(msg) +#define _GL_ATTRIBUTE_WARNING(msg) +#endif +#endif + +/* _GL_ATTRIBUTE_EXTERNALLY_VISIBLE declares that the entity should remain + visible to debuggers etc., even with '-fwhole-program'. */ +/* Applies to: functions, variables. */ +#ifndef _GL_ATTRIBUTE_EXTERNALLY_VISIBLE +#if _GL_HAS_ATTRIBUTE(externally_visible) +#define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE __attribute__((externally_visible)) +#else +#define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE +#endif +#endif + +/* _GL_ATTRIBUTE_FALLTHROUGH declares that it is not a programming mistake if + the control flow falls through to the immediately following 'case' or + 'default' label. The compiler should not warn in this case. */ +/* Applies to: Empty statement (;), inside a 'switch' statement. */ +/* Always expands to something. */ +#ifndef _GL_ATTRIBUTE_FALLTHROUGH +#if _GL_HAVE___HAS_C_ATTRIBUTE +#if __has_c_attribute(__fallthrough__) +#define _GL_ATTRIBUTE_FALLTHROUGH [[__fallthrough__]] +#endif +#endif +#if !defined _GL_ATTRIBUTE_FALLTHROUGH && _GL_HAS_ATTRIBUTE(fallthrough) +#define _GL_ATTRIBUTE_FALLTHROUGH __attribute__((__fallthrough__)) +#endif +#ifndef _GL_ATTRIBUTE_FALLTHROUGH +#define _GL_ATTRIBUTE_FALLTHROUGH ((void)0) +#endif +#endif + +/* _GL_ATTRIBUTE_FORMAT ((ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK)) + declares that the STRING-INDEXth function argument is a format string of + style ARCHETYPE, which is one of: + printf, gnu_printf + scanf, gnu_scanf, + strftime, gnu_strftime, + strfmon, + or the same thing prefixed and suffixed with '__'. + If FIRST-TO-CHECK is not 0, arguments starting at FIRST-TO_CHECK + are suitable for the format string. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_FORMAT +#if _GL_HAS_ATTRIBUTE(format) +#define _GL_ATTRIBUTE_FORMAT(spec) __attribute__((__format__ spec)) +#else +#define _GL_ATTRIBUTE_FORMAT(spec) +#endif +#endif + +/* _GL_ATTRIBUTE_LEAF declares that if the function is called from some other + compilation unit, it executes code from that unit only by return or by + exception handling. This declaration lets the compiler optimize that unit + more aggressively. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_LEAF +#if _GL_HAS_ATTRIBUTE(leaf) +#define _GL_ATTRIBUTE_LEAF __attribute__((__leaf__)) +#else +#define _GL_ATTRIBUTE_LEAF +#endif +#endif + +/* _GL_ATTRIBUTE_MALLOC declares that the function returns a pointer to freshly + allocated memory. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_MALLOC +#if _GL_HAS_ATTRIBUTE(malloc) +#define _GL_ATTRIBUTE_MALLOC __attribute__((__malloc__)) +#else +#define _GL_ATTRIBUTE_MALLOC +#endif +#endif + +/* _GL_ATTRIBUTE_MAY_ALIAS declares that pointers to the type may point to the + same storage as pointers to other types. Thus this declaration disables + strict aliasing optimization. */ +/* Applies to: types. */ +/* Oracle Studio 12.6 mishandles may_alias despite __has_attribute OK. */ +#ifndef _GL_ATTRIBUTE_MAY_ALIAS +#if _GL_HAS_ATTRIBUTE(may_alias) && !defined __SUNPRO_C +#define _GL_ATTRIBUTE_MAY_ALIAS __attribute__((__may_alias__)) +#else +#define _GL_ATTRIBUTE_MAY_ALIAS +#endif +#endif + +/* _GL_ATTRIBUTE_MAYBE_UNUSED declares that it is not a programming mistake if + the entity is not used. The compiler should not warn if the entity is not + used. */ +/* Applies to: + - function, variable, + - struct, union, struct/union member, + - enumeration, enumeration item, + - typedef, + in C++ also: class. */ +/* In C++ and C23, this is spelled [[__maybe_unused__]]. + GCC's syntax is __attribute__ ((__unused__)). + clang supports both syntaxes. Except that with clang ≥ 6, < 10, in C++ mode, + __has_c_attribute (__maybe_unused__) yields true but the use of + [[__maybe_unused__]] nevertheless produces a warning. */ +#ifndef _GL_ATTRIBUTE_MAYBE_UNUSED +#ifndef _GL_BRACKET_BEFORE_ATTRIBUTE +#if defined __clang__ && defined __cplusplus +#if !defined __apple_build_version__ && __clang_major__ >= 10 +#define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]] +#endif +#elif _GL_HAVE___HAS_C_ATTRIBUTE +#if __has_c_attribute(__maybe_unused__) +#define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]] +#endif +#endif +#endif +#ifndef _GL_ATTRIBUTE_MAYBE_UNUSED +#define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED +#endif +#endif +/* Alternative spelling of this macro, for convenience and for + compatibility with glibc/include/libc-symbols.h. */ +#define _GL_UNUSED _GL_ATTRIBUTE_MAYBE_UNUSED +/* Earlier spellings of this macro. */ +#define _UNUSED_PARAMETER_ _GL_ATTRIBUTE_MAYBE_UNUSED + +/* _GL_ATTRIBUTE_NODISCARD declares that the caller of the function should not + discard the return value. The compiler may warn if the caller does not use + the return value, unless the caller uses something like ignore_value. */ +/* Applies to: function, enumeration, class. */ +#ifndef _GL_ATTRIBUTE_NODISCARD +#ifndef _GL_BRACKET_BEFORE_ATTRIBUTE +#if defined __clang__ && defined __cplusplus +/* With clang up to 15.0.6 (at least), in C++ mode, [[__nodiscard__]] produces + a warning. + The 1000 below means a yet unknown threshold. When clang++ version X + starts supporting [[__nodiscard__]] without warning about it, you can + replace the 1000 with X. */ +#if __clang_major__ >= 1000 +#define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]] +#endif +#elif _GL_HAVE___HAS_C_ATTRIBUTE +#if __has_c_attribute(__nodiscard__) +#define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]] +#endif +#endif +#endif +#if !defined _GL_ATTRIBUTE_NODISCARD && _GL_HAS_ATTRIBUTE(warn_unused_result) +#define _GL_ATTRIBUTE_NODISCARD __attribute__((__warn_unused_result__)) +#endif +#ifndef _GL_ATTRIBUTE_NODISCARD +#define _GL_ATTRIBUTE_NODISCARD +#endif +#endif + +/* _GL_ATTRIBUTE_NOINLINE tells that the compiler should not inline the + function. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_NOINLINE +#if _GL_HAS_ATTRIBUTE(noinline) +#define _GL_ATTRIBUTE_NOINLINE __attribute__((__noinline__)) +#else +#define _GL_ATTRIBUTE_NOINLINE +#endif +#endif + +/* _GL_ATTRIBUTE_NONNULL ((N1, N2,...)) declares that the arguments N1, N2,... + must not be NULL. + _GL_ATTRIBUTE_NONNULL () declares that all pointer arguments must not be + null. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_NONNULL +#if _GL_HAS_ATTRIBUTE(nonnull) +#define _GL_ATTRIBUTE_NONNULL(args) __attribute__((__nonnull__ args)) +#else +#define _GL_ATTRIBUTE_NONNULL(args) +#endif +#endif + +/* _GL_ATTRIBUTE_NONSTRING declares that the contents of a character array is + not meant to be NUL-terminated. */ +/* Applies to: struct/union members and variables that are arrays of element + type '[[un]signed] char'. */ +#ifndef _GL_ATTRIBUTE_NONSTRING +#if _GL_HAS_ATTRIBUTE(nonstring) +#define _GL_ATTRIBUTE_NONSTRING __attribute__((__nonstring__)) +#else +#define _GL_ATTRIBUTE_NONSTRING +#endif +#endif + +/* There is no _GL_ATTRIBUTE_NORETURN; use _Noreturn instead. */ + +/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions. + */ +/* Applies to: functions. */ +/* After a function's parameter list, this attribute must come first, before + other attributes. */ +#ifndef _GL_ATTRIBUTE_NOTHROW +#if defined __cplusplus +#if _GL_GNUC_PREREQ(2, 8) || __clang_major__ >= 4 +#if __cplusplus >= 201103L +#define _GL_ATTRIBUTE_NOTHROW noexcept(true) +#else +#define _GL_ATTRIBUTE_NOTHROW throw() +#endif +#else +#define _GL_ATTRIBUTE_NOTHROW +#endif +#else +#if _GL_HAS_ATTRIBUTE(nothrow) +#define _GL_ATTRIBUTE_NOTHROW __attribute__((__nothrow__)) +#else +#define _GL_ATTRIBUTE_NOTHROW +#endif +#endif +#endif + +/* _GL_ATTRIBUTE_PACKED declares: + For struct members: The member has the smallest possible alignment. + For struct, union, class: All members have the smallest possible alignment, + minimizing the memory required. */ +/* Applies to: struct members, struct, union, + in C++ also: class. */ +#ifndef _GL_ATTRIBUTE_PACKED +/* Oracle Studio 12.6 miscompiles code with __attribute__ ((__packed__)) despite + __has_attribute OK. */ +#if _GL_HAS_ATTRIBUTE(packed) && !defined __SUNPRO_C +#define _GL_ATTRIBUTE_PACKED __attribute__((__packed__)) +#else +#define _GL_ATTRIBUTE_PACKED +#endif +#endif + +/* _GL_ATTRIBUTE_PURE declares: + It is OK for a compiler to move calls to the function and to omit + calls to the function if another call has the same arguments or the + result is not used, and if observable state is the same. + This attribute is safe for a function that does not affect observable state + and always returns exactly once. + (This attribute is looser than _GL_ATTRIBUTE_CONST because the function + can depend on observable state. It is stricter than + _GL_ATTRIBUTE_REPRODUCIBLE because the function must return exactly + once and cannot affect state addressed by its arguments.) */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_PURE +#if _GL_HAS_ATTRIBUTE(pure) +#define _GL_ATTRIBUTE_PURE __attribute__((__pure__)) +#else +#define _GL_ATTRIBUTE_PURE _GL_ATTRIBUTE_REPRODUCIBLE +#endif +#endif + +/* _GL_ATTRIBUTE_REPRODUCIBLE declares: + It is OK for a compiler to move calls to the function and to omit duplicate + calls to the function with the same arguments, so long as the state + addressed by its arguments is the same and is updated in time for + the rest of the program. + This attribute is safe for a function that is effectless and idempotent; see + ISO C 23 § 6.7.12.7 for a definition of these terms. + (This attribute is looser than _GL_ATTRIBUTE_UNSEQUENCED because + the function need not be stateless and idempotent. It is looser + than _GL_ATTRIBUTE_PURE because the function need not return + exactly once and can affect state addressed by its arguments.) + See also and + . + ATTENTION! Efforts are underway to change the meaning of this attribute. + See . */ +/* Applies to: functions, pointer to functions, function types. */ +#ifndef _GL_ATTRIBUTE_REPRODUCIBLE +/* This may be revisited when gcc and clang support [[reproducible]] or possibly + __attribute__ ((__reproducible__)). */ +#ifndef _GL_BRACKET_BEFORE_ATTRIBUTE +#if _GL_HAS_ATTRIBUTE(reproducible) +#define _GL_ATTRIBUTE_REPRODUCIBLE [[reproducible]] +#endif +#endif +#ifndef _GL_ATTRIBUTE_REPRODUCIBLE +#define _GL_ATTRIBUTE_REPRODUCIBLE +#endif +#endif + +/* _GL_ATTRIBUTE_RETURNS_NONNULL declares that the function's return value is + a non-NULL pointer. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_RETURNS_NONNULL +#if _GL_HAS_ATTRIBUTE(returns_nonnull) +#define _GL_ATTRIBUTE_RETURNS_NONNULL __attribute__((__returns_nonnull__)) +#else +#define _GL_ATTRIBUTE_RETURNS_NONNULL +#endif +#endif + +/* _GL_ATTRIBUTE_SENTINEL(pos) declares that the variadic function expects a + trailing NULL argument. + _GL_ATTRIBUTE_SENTINEL () - The last argument is NULL (requires C99). + _GL_ATTRIBUTE_SENTINEL ((N)) - The (N+1)st argument from the end is NULL. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_SENTINEL +#if _GL_HAS_ATTRIBUTE(sentinel) +#define _GL_ATTRIBUTE_SENTINEL(pos) __attribute__((__sentinel__ pos)) +#else +#define _GL_ATTRIBUTE_SENTINEL(pos) +#endif +#endif + +/* _GL_ATTRIBUTE_UNSEQUENCED declares: + It is OK for a compiler to move calls to the function and to omit duplicate + calls to the function with the same arguments, so long as the state + addressed by its arguments is the same. + This attribute is safe for a function that is effectless, idempotent, + stateless, and independent; see ISO C 23 § 6.7.12.7 for a definition of + these terms. + (This attribute is stricter than _GL_ATTRIBUTE_REPRODUCIBLE because + the function must be stateless and independent. It is looser than + _GL_ATTRIBUTE_CONST because the function need not return exactly + once and can depend on state addressed by its arguments.) + See also and + . + ATTENTION! Efforts are underway to change the meaning of this attribute. + See . */ +/* Applies to: functions, pointer to functions, function types. */ +#ifndef _GL_ATTRIBUTE_UNSEQUENCED +/* This may be revisited when gcc and clang support [[unsequenced]] or possibly + __attribute__ ((__unsequenced__)). */ +#ifndef _GL_BRACKET_BEFORE_ATTRIBUTE +#if _GL_HAS_ATTRIBUTE(unsequenced) +#define _GL_ATTRIBUTE_UNSEQUENCED [[unsequenced]] +#endif +#endif +#ifndef _GL_ATTRIBUTE_UNSEQUENCED +#define _GL_ATTRIBUTE_UNSEQUENCED +#endif +#endif + +/* A helper macro. Don't use it directly. */ +#ifndef _GL_ATTRIBUTE_UNUSED +#if _GL_HAS_ATTRIBUTE(unused) +#define _GL_ATTRIBUTE_UNUSED __attribute__((__unused__)) +#else +#define _GL_ATTRIBUTE_UNUSED +#endif +#endif + +/* _GL_UNUSED_LABEL; declares that it is not a programming mistake if the + immediately preceding label is not used. The compiler should not warn + if the label is not used. */ +/* Applies to: label (both in C and C++). */ +/* Note that g++ < 4.5 does not support the '__attribute__ ((__unused__)) ;' + syntax. But clang does. */ +#ifndef _GL_UNUSED_LABEL +#if !(defined __cplusplus && !_GL_GNUC_PREREQ(4, 5)) || defined __clang__ +#define _GL_UNUSED_LABEL _GL_ATTRIBUTE_UNUSED +#else +#define _GL_UNUSED_LABEL +#endif +#endif + +/* The following attributes enable detection of multithread-safety problems + and resource leaks at compile-time, by clang ≥ 15, when the warning option + -Wthread-safety is enabled. For usage, see + . */ +#ifndef _GL_ATTRIBUTE_CAPABILITY_TYPE +#if __clang_major__ >= 15 +#define _GL_ATTRIBUTE_CAPABILITY_TYPE(concept) \ + __attribute__((__capability__(concept))) +#else +#define _GL_ATTRIBUTE_CAPABILITY_TYPE(concept) +#endif +#endif +#ifndef _GL_ATTRIBUTE_ACQUIRE_CAPABILITY +#if __clang_major__ >= 15 +#define _GL_ATTRIBUTE_ACQUIRE_CAPABILITY(resource) \ + __attribute__((__acquire_capability__(resource))) +#else +#define _GL_ATTRIBUTE_ACQUIRE_CAPABILITY(resource) +#endif +#endif +#ifndef _GL_ATTRIBUTE_RELEASE_CAPABILITY +#if __clang_major__ >= 15 +#define _GL_ATTRIBUTE_RELEASE_CAPABILITY(resource) \ + __attribute__((__release_capability__(resource))) +#else +#define _GL_ATTRIBUTE_RELEASE_CAPABILITY(resource) +#endif +#endif + +/* In C++, there is the concept of "language linkage", that encompasses + name mangling and function calling conventions. + The following macros start and end a block of "C" linkage. */ +#ifdef __cplusplus +#define _GL_BEGIN_C_LINKAGE extern "C" { +#define _GL_END_C_LINKAGE } +#else +#define _GL_BEGIN_C_LINKAGE +#define _GL_END_C_LINKAGE +#endif + +/* Hidden symbol. */ +/* #undef frexp */ + +/* Hidden symbol. */ +/* #undef frexpl */ + +/* Define to '__inline__' or '__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to long or long long if and don't define. */ +/* #undef intmax_t */ + +/* Work around a bug in Apple GCC 4.0.1 build 5465: In C99 mode, it supports + the ISO C 99 semantics of 'extern inline' (unlike the GNU C semantics of + earlier versions), but does not display it by setting __GNUC_STDC_INLINE__. + __APPLE__ && __MACH__ test for Mac OS X. + __APPLE_CC__ tests for the Apple compiler and its version. + __STDC_VERSION__ tests for the C99 mode. */ +#if defined __APPLE__ && defined __MACH__ && __APPLE_CC__ >= 5465 && \ + !defined __cplusplus && __STDC_VERSION__ >= 199901L && \ + !defined __GNUC_STDC_INLINE__ +#define __GNUC_STDC_INLINE__ 1 +#endif + +/* Hidden symbol. */ +/* #undef mbrtowc */ + +/* Hidden symbol. */ +/* #undef mbsinit */ + +/* Define to a type if does not define. */ +/* #undef mbstate_t */ + +/* Hidden symbol. */ +/* #undef memchr */ + +/* _GL_CMP (n1, n2) performs a three-valued comparison on n1 vs. n2, where + n1 and n2 are expressions without side effects, that evaluate to real + numbers (excluding NaN). + It returns + 1 if n1 > n2 + 0 if n1 == n2 + -1 if n1 < n2 + The naïve code (n1 > n2 ? 1 : n1 < n2 ? -1 : 0) produces a conditional + jump with nearly all GCC versions up to GCC 10. + This variant (n1 < n2 ? -1 : n1 > n2) produces a conditional with many + GCC versions up to GCC 9. + The better code (n1 > n2) - (n1 < n2) from Hacker's Delight § 2-9 + avoids conditional jumps in all GCC versions >= 3.4. */ +#define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2))) + +/* Define to 'int' if does not define. */ +/* #undef mode_t */ + +/* Define as a signed integer type capable of holding a process identifier. */ +/* #undef pid_t */ + +/* Define as the type of the result of subtracting two pointers, if the system + doesn't define it. */ +/* #undef ptrdiff_t */ + +/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported only directly. */ +#define restrict __restrict__ +/* Work around a bug in older versions of Sun C++, which did not + #define __restrict__ or support _Restrict or __restrict__ + even though the corresponding Sun C compiler ended up with + "#define restrict _Restrict" or "#define restrict __restrict__" + in the previous line. This workaround can be removed once + we assume Oracle Developer Studio 12.5 (2016) or later. */ +#if defined __SUNPRO_CC && !defined __RESTRICT && !defined __restrict__ +#define _Restrict +#define __restrict__ +#endif + +/* Hidden symbol. */ +/* #undef rpl_fgetc */ + +/* Hidden symbol. */ +/* #undef rpl_fgets */ + +/* Hidden symbol. */ +/* #undef rpl_fprintf */ + +/* Hidden symbol. */ +/* #undef rpl_fputc */ + +/* Hidden symbol. */ +/* #undef rpl_fputs */ + +/* Hidden symbol. */ +/* #undef rpl_fread */ + +/* Hidden symbol. */ +/* #undef rpl_frexp */ + +/* Hidden symbol. */ +/* #undef rpl_frexpl */ + +/* Hidden symbol. */ +/* #undef rpl_fscanf */ + +/* Hidden symbol. */ +/* #undef rpl_fwrite */ + +/* Hidden symbol. */ +/* #undef rpl_mbrtowc */ + +/* Hidden symbol. */ +/* #undef rpl_mbsinit */ + +/* Hidden symbol. */ +/* #undef rpl_memchr */ + +/* Hidden symbol. */ +/* #undef rpl_tdelete */ + +/* Hidden symbol. */ +/* #undef rpl_tfind */ + +/* Hidden symbol. */ +/* #undef rpl_tsearch */ + +/* Hidden symbol. */ +/* #undef rpl_twalk */ + +/* Hidden symbol. */ +/* #undef rpl_vfprintf */ + +/* Define as 'unsigned int' if doesn't define. */ +/* #undef size_t */ + +/* Define as a signed type of the same size as size_t. */ +/* #undef ssize_t */ + +/* Hidden symbol. */ +/* #undef tdelete */ + +/* Hidden symbol. */ +/* #undef tfind */ + +/* Hidden symbol. */ +/* #undef tsearch */ + +/* Hidden symbol. */ +/* #undef twalk */ + +#define __libc_lock_t gl_lock_t +#define __libc_lock_define gl_lock_define +#define __libc_lock_define_initialized gl_lock_define_initialized +#define __libc_lock_init gl_lock_init +#define __libc_lock_lock gl_lock_lock +#define __libc_lock_unlock gl_lock_unlock +#define __libc_lock_recursive_t gl_recursive_lock_t +#define __libc_lock_define_recursive gl_recursive_lock_define +#define __libc_lock_define_initialized_recursive \ + gl_recursive_lock_define_initialized +#define __libc_lock_init_recursive gl_recursive_lock_init +#define __libc_lock_lock_recursive gl_recursive_lock_lock +#define __libc_lock_unlock_recursive gl_recursive_lock_unlock + +#define asnprintf _libintl_asnprintf +#define rpl_asnprintf _libintl_asnprintf +/* Symbols defined by main intl code. The prefix '_nl_' is used by glibc. + For hiding the symbols on AIX and Solaris 10 with compilers that don't + support the __visibility__ attribute, map them to prefix '_libintl_'. */ +#define _nl_explode_name _libintl_explode_name +#define _nl_find_domain _libintl_find_domain +#define _nl_find_msg _libintl_find_msg +#define _nl_language_preferences_default _libintl_language_preferences_default +#define _nl_load_domain _libintl_load_domain +#define _nl_log_untranslated _libintl_log_untranslated +#define _nl_make_l10nflist _libintl_make_l10nflist +#define _nl_normalize_codeset _libintl_normalize_codeset +#define _nl_state_lock _libintl_state_lock +/* Symbols defined by gnulib module 'float'. */ +#define gl_LDBL_MAX _libintl_LDBL_MAX +/* Symbols defined by gnulib module 'free-posix'. */ +#define rpl_free _libintl_free +/* Symbols defined by gnulib module 'hard-locale'. */ +#define hard_locale _libintl_hard_locale +/* Symbols defined by gnulib module 'isnand-nolibm'. */ +#define rpl_isnand _libintl_isnand +/* Symbols defined by gnulib module 'isnanf-nolibm'. */ +#define rpl_isnanf _libintl_isnanf +/* Symbols defined by gnulib module 'isnanl-nolibm'. */ +#define rpl_isnanl _libintl_isnanl +/* Symbols defined by gnulib module 'localename'. */ +#define gl_locale_name_thread _libintl_locale_name_thread +#define gl_locale_name_posix _libintl_locale_name_posix +#define gl_locale_name _libintl_locale_name +/* Symbols defined by gnulib module 'localename-unsafe'. */ +#define gl_locale_name_canonicalize _libintl_locale_name_canonicalize +#define gl_locale_name_from_win32_LANGID _libintl_locale_name_from_win32_LANGID +#define gl_locale_name_from_win32_LCID _libintl_locale_name_from_win32_LCID +#define gl_locale_name_thread_unsafe _libintl_locale_name_thread_unsafe +#define gl_locale_name_posix_unsafe _libintl_locale_name_posix_unsafe +#define gl_locale_name_environ _libintl_locale_name_environ +#define gl_locale_name_default _libintl_locale_name_default +#define gl_locale_name_unsafe _libintl_locale_name_unsafe +#define rpl_newlocale _libintl_newlocale +#define rpl_duplocale _libintl_duplocale +#define rpl_freelocale _libintl_freelocale +/* Symbols defined by gnulib module 'lock'. */ +#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS +#define glthread_lock_init _libintl_lock_init +#define glthread_lock_lock _libintl_lock_lock +#define glthread_lock_unlock _libintl_lock_unlock +#define glthread_lock_destroy _libintl_lock_destroy +#define glthread_rwlock_init _libintl_rwlock_init +#define glthread_rwlock_rdlock _libintl_rwlock_rdlock +#define glthread_rwlock_wrlock _libintl_rwlock_wrlock +#define glthread_rwlock_unlock _libintl_rwlock_unlock +#define glthread_rwlock_destroy _libintl_rwlock_destroy +#define glthread_recursive_lock_init _libintl_recursive_lock_init +#define glthread_recursive_lock_lock _libintl_recursive_lock_lock +#define glthread_recursive_lock_unlock _libintl_recursive_lock_unlock +#define glthread_recursive_lock_destroy _libintl_recursive_lock_destroy +#endif +#define glthread_rwlock_init_for_glibc _libintl_rwlock_init_for_glibc +#define glthread_rwlock_init_multithreaded _libintl_rwlock_init_multithreaded +#define glthread_rwlock_rdlock_multithreaded \ + _libintl_rwlock_rdlock_multithreaded +#define glthread_rwlock_wrlock_multithreaded \ + _libintl_rwlock_wrlock_multithreaded +#define glthread_rwlock_unlock_multithreaded \ + _libintl_rwlock_unlock_multithreaded +#define glthread_rwlock_destroy_multithreaded \ + _libintl_rwlock_destroy_multithreaded +#define glthread_recursive_lock_init_multithreaded \ + _libintl_recursive_lock_init_multithreaded +#define glthread_recursive_lock_lock_multithreaded \ + _libintl_recursive_lock_lock_multithreaded +#define glthread_recursive_lock_unlock_multithreaded \ + _libintl_recursive_lock_unlock_multithreaded +#define glthread_recursive_lock_destroy_multithreaded \ + _libintl_recursive_lock_destroy_multithreaded +#define glthread_once_singlethreaded _libintl_once_singlethreaded +#define glthread_once_multithreaded _libintl_once_multithreaded +/* Symbols defined by gnulib module 'mbszero'. */ +#define mbszero _libintl_mbszero +/* Symbols defined by gnulib module 'printf-frexp'. */ +#define printf_frexp _libintl_printf_frexp +/* Symbols defined by gnulib module 'printf-frexpl'. */ +#define printf_frexpl _libintl_printf_frexpl +/* Symbols defined by gnulib module 'setlocale-null'. */ +#define setlocale_null _libintl_setlocale_null +#define setlocale_null_r _libintl_setlocale_null_r +/* Symbols defined by gnulib module 'setlocale-null-unlocked'. */ +#define setlocale_null_unlocked _libintl_setlocale_null_unlocked +#define setlocale_null_r_unlocked _libintl_setlocale_null_r_unlocked +/* Symbols defined by gnulib module 'signbit'. */ +#define gl_signbitf _libintl_signbitf +#define gl_signbitd _libintl_signbitd +#define gl_signbitl _libintl_signbitl +/* Symbols defined by gnulib module 'threadlib'. */ +#define glthread_in_use _libintl_glthread_in_use +/* Symbols defined by gnulib module 'vasnprintf'. */ +#define printf_fetchargs _libintl_printf_fetchargs +#define printf_parse _libintl_printf_parse +#define vasnprintf _libintl_vasnprintf +#define rpl_vasnprintf _libintl_vasnprintf +/* Symbols defined by gnulib module 'vasnwprintf'. */ +#define asnwprintf _libintl_asnwprintf +#define wprintf_parse _libintl_wprintf_parse +#define vasnwprintf _libintl_vasnwprintf +/* Symbols defined by gnulib module 'windows-mutex'. */ +#define glwthread_mutex_init _libintl_glwthread_mutex_init +#define glwthread_mutex_lock _libintl_glwthread_mutex_lock +#define glwthread_mutex_trylock _libintl_glwthread_mutex_trylock +#define glwthread_mutex_unlock _libintl_glwthread_mutex_unlock +#define glwthread_mutex_destroy _libintl_glwthread_mutex_destroy +/* Symbols defined by gnulib module 'windows-once'. */ +#define glwthread_once _libintl_glwthread_once +/* Symbols defined by gnulib module 'windows-recmutex'. */ +#define glwthread_recmutex_init _libintl_glwthread_recmutex_init +#define glwthread_recmutex_lock _libintl_glwthread_recmutex_lock +#define glwthread_recmutex_trylock _libintl_glwthread_recmutex_trylock +#define glwthread_recmutex_unlock _libintl_glwthread_recmutex_unlock +#define glwthread_recmutex_destroy _libintl_glwthread_recmutex_destroy +/* Symbols defined by gnulib module 'windows-rwlock'. */ +#define glwthread_rwlock_init _libintl_glwthread_rwlock_init +#define glwthread_rwlock_rdlock _libintl_glwthread_rwlock_rdlock +#define glwthread_rwlock_wrlock _libintl_glwthread_rwlock_wrlock +#define glwthread_rwlock_tryrdlock _libintl_glwthread_rwlock_tryrdlock +#define glwthread_rwlock_trywrlock _libintl_glwthread_rwlock_trywrlock +#define glwthread_rwlock_unlock _libintl_glwthread_rwlock_unlock +#define glwthread_rwlock_destroy _libintl_glwthread_rwlock_destroy +/* Symbols defined by gnulib module 'xsize'. */ +#define xmax _libintl_xmax +#define xsum _libintl_xsum +#define xsum3 _libintl_xsum3 +#define xsum4 _libintl_xsum4 + +#if !(defined __cplusplus \ + ? 1 \ + : (defined __clang__ \ + ? __STDC_VERSION__ >= 202000L && __clang_major__ >= 15 \ + : (defined __GNUC__ \ + ? __STDC_VERSION__ >= 202000L && __GNUC__ >= 13 \ + : defined HAVE_C_BOOL))) +#if !defined __cplusplus && !defined __bool_true_false_are_defined +#if HAVE_STDBOOL_H +#include +#else +#if defined __SUNPRO_C +#error \ + " is not usable with this configuration. To make it usable, add -D_STDC_C99= to $CC." +#else +#error \ + " does not exist on this platform. Use gnulib module 'stdbool-c99' instead of gnulib module 'stdbool'." +#endif +#endif +#endif +#if !true +#define true (!false) +#endif +#endif + +#if (!(defined __clang__ \ + ? (defined __cplusplus \ + ? __cplusplus >= 201703L \ + : __STDC_VERSION__ >= 202000L && __clang_major__ >= 16 && \ + !defined __sun) \ + : (defined __GNUC__ \ + ? (defined __cplusplus \ + ? __cplusplus >= 201103L && __GNUG__ >= 6 \ + : __STDC_VERSION__ >= 202000L && __GNUC__ >= 13 && \ + !defined __sun) \ + : defined HAVE_C_STATIC_ASSERT)) && \ + !defined assert && \ + (!defined __cplusplus || \ + (__cpp_static_assert < 201411 && __GNUG__ < 6 && __clang_major__ < 6))) +#include +#undef /**/ assert +#ifdef __sgi +#undef /**/ __ASSERT_H__ +#endif +/* Solaris 11.4 defines static_assert as a macro with 2 arguments. + We need it also to be invocable with a single argument. + Haiku 2022 does not define static_assert at all. */ +#if (__STDC_VERSION__ - 0 >= 201112L) && !defined __cplusplus +#undef /**/ static_assert +#define static_assert _Static_assert +#endif +#endif + +/* Tweak gnulib code according to the needs of this library. */ +#define IN_LIBINTL 1 + +/* On Windows, variables that may be in a DLL must be marked specially. + The symbols marked with DLL_VARIABLE should be exported if and only if the + object file gets included in a DLL. Libtool, on Windows platforms, defines + the C macro DLL_EXPORT (together with PIC) when compiling for a shared + library (called DLL under Windows) and does not define it when compiling + an object file meant to be linked statically into some executable. */ +#if (defined _MSC_VER && defined DLL_EXPORT) && !defined IN_RELOCWRAPPER +#define DLL_VARIABLE __declspec(dllimport) +#else +#define DLL_VARIABLE +#endif + +/* Extra OS/2 (emx+gcc) defines. */ +#if defined __EMX__ && !defined __KLIBC__ +#include "os2compat.h" +#endif + +/* ADDED FOR GHOSTTY. This is needed to ensure that all gnulib-lib + * source files have the locale_t type and all the LC_ constants. + * It looks like some files do this and some don't so we just put it + * here to ensure we always have it. This surely can't be the best or + * correct way to do this but it works. + * + * When upgrading gettext we just need to be careful about this. This + * is noted in the build.zig as well. + */ +#if HAVE_GOOD_USELOCALE +/* Mac OS X 10.5 defines the locale_t type in . */ +#if defined __APPLE__ && defined __MACH__ +#include +#endif +#endif From 4cf127a06481f3dbcc23cec3c300f55253d03dfb Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 08:40:39 -0800 Subject: [PATCH 05/17] build: i18n should emit mo on every platform --- build.zig | 10 ++++++++++ src/build/GhosttyI18n.zig | 25 ++++++++++++------------- src/os/i18n.zig | 3 +++ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/build.zig b/build.zig index 4e96a5bbf..f07918441 100644 --- a/build.zig +++ b/build.zig @@ -82,6 +82,16 @@ pub fn build(b: *std.Build) !void { { const run_cmd = b.addRunArtifact(exe.exe); if (b.args) |args| run_cmd.addArgs(args); + + // Set the proper resources dir so things like shell integration + // work correctly. If we're running `zig build run` in Ghostty, + // this also ensures it overwrites the release one with our debug + // build. + run_cmd.setEnvironmentVariable( + "GHOSTTY_RESOURCES_DIR", + b.getInstallPath(.prefix, "share/ghostty"), + ); + const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); } diff --git a/src/build/GhosttyI18n.zig b/src/build/GhosttyI18n.zig index 5ca564268..b7aa0be11 100644 --- a/src/build/GhosttyI18n.zig +++ b/src/build/GhosttyI18n.zig @@ -18,23 +18,22 @@ steps: []*std.Build.Step, update_step: *std.Build.Step, pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n { + _ = cfg; + var steps = std.ArrayList(*std.Build.Step).init(b.allocator); defer steps.deinit(); - if (cfg.app_runtime == .gtk) { - // Output the .mo files used by the GTK apprt - inline for (locales) |locale| { - const msgfmt = b.addSystemCommand(&.{ "msgfmt", "-o", "-" }); - msgfmt.addFileArg(b.path("po/" ++ locale ++ ".po")); + inline for (locales) |locale| { + const msgfmt = b.addSystemCommand(&.{ "msgfmt", "-o", "-" }); + msgfmt.addFileArg(b.path("po/" ++ locale ++ ".po")); - try steps.append(&b.addInstallFile( - msgfmt.captureStdOut(), - std.fmt.comptimePrint( - "share/locale/{s}/LC_MESSAGES/{s}.mo", - .{ locale, domain }, - ), - ).step); - } + try steps.append(&b.addInstallFile( + msgfmt.captureStdOut(), + std.fmt.comptimePrint( + "share/locale/{s}/LC_MESSAGES/{s}.mo", + .{ locale, domain }, + ), + ).step); } return .{ diff --git a/src/os/i18n.zig b/src/os/i18n.zig index d6124cac5..668e22c7d 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -1,6 +1,8 @@ const std = @import("std"); const build_config = @import("../build_config.zig"); +const log = std.log.scoped(.i18n); + pub const InitError = error{ InvalidResourcesDir, OutOfMemory, @@ -26,6 +28,7 @@ pub fn init(resources_dir: []const u8) InitError!void { return error.OutOfMemory; // Bind our bundle ID to the given locale path + log.debug("binding domain={s} path={s}", .{ build_config.bundle_id, path }); _ = bindtextdomain(build_config.bundle_id, path.ptr) orelse return error.OutOfMemory; } From 238573d42eda5cddf0548cfa60b81b8958597a75 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 08:50:04 -0800 Subject: [PATCH 06/17] i18n: export proper _ function --- src/os/i18n.zig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/os/i18n.zig b/src/os/i18n.zig index 668e22c7d..c4609bff8 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -33,9 +33,14 @@ pub fn init(resources_dir: []const u8) InitError!void { return error.OutOfMemory; } +/// Translate a message for the Ghostty domain. +pub fn _(msgid: [*:0]const u8) [*:0]const u8 { + return dgettext(build_config.bundle_id, msgid); +} + // Manually include function definitions for the gettext functions // as libintl.h isn't always easily available (e.g. in musl) extern fn bindtextdomain(domainname: [*:0]const u8, dirname: [*:0]const u8) ?[*:0]const u8; extern fn textdomain(domainname: [*:0]const u8) ?[*:0]const u8; -pub extern fn gettext(msgid: [*:0]const u8) [*:0]const u8; -pub const _ = gettext; +extern fn gettext(msgid: [*:0]const u8) [*:0]const u8; +extern fn dgettext(domainname: [*:0]const u8, msgid: [*:0]const u8) [*:0]const u8; From edf619205c7972b90dd6d99b9cbf3d9942c0c8b3 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 09:26:57 -0800 Subject: [PATCH 07/17] add ghostty_translate C API --- include/ghostty.h | 1 + macos/Ghostty.xcodeproj/project.pbxproj | 20 +++++++++++-------- .../xcshareddata/xcschemes/Ghostty.xcscheme | 1 + src/build/GhosttyI18n.zig | 9 +++------ src/main_c.zig | 11 ++++++++++ src/os/i18n.zig | 7 +++++++ 6 files changed, 35 insertions(+), 14 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index 4fc180a1a..2dc1bffef 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -669,6 +669,7 @@ typedef struct { int ghostty_init(void); void ghostty_cli_main(uintptr_t, char**); ghostty_info_s ghostty_info(void); +const char* ghostty_translate(const char*); ghostty_config_t ghostty_config_new(); void ghostty_config_free(ghostty_config_t); diff --git a/macos/Ghostty.xcodeproj/project.pbxproj b/macos/Ghostty.xcodeproj/project.pbxproj index 0c68da534..b4c00946c 100644 --- a/macos/Ghostty.xcodeproj/project.pbxproj +++ b/macos/Ghostty.xcodeproj/project.pbxproj @@ -40,6 +40,7 @@ A53D0C952B53B4D800305CE6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; }; A53D0C9B2B543F3B00305CE6 /* Ghostty.App.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53D0C992B543F3B00305CE6 /* Ghostty.App.swift */; }; A53D0C9C2B543F7B00305CE6 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BB729B6F53A0055DE60 /* Package.swift */; }; + A546F1142D7B68D7003B11A0 /* locale in Resources */ = {isa = PBXBuildFile; fileRef = A546F1132D7B68D7003B11A0 /* locale */; }; A54B0CE92D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54B0CE82D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift */; }; A54B0CEB2D0CFB4C00CBEFF8 /* NSImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54B0CEA2D0CFB4A00CBEFF8 /* NSImage+Extension.swift */; }; A54B0CED2D0CFB7700CBEFF8 /* ColorizedGhosttyIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54B0CEC2D0CFB7300CBEFF8 /* ColorizedGhosttyIcon.swift */; }; @@ -138,6 +139,7 @@ A53A6C022CCC1B7D00943E98 /* Ghostty.Action.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Action.swift; sourceTree = ""; }; A53D0C932B53B43700305CE6 /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = ""; }; A53D0C992B543F3B00305CE6 /* Ghostty.App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.App.swift; sourceTree = ""; }; + A546F1132D7B68D7003B11A0 /* locale */ = {isa = PBXFileReference; lastKnownFileType = folder; name = locale; path = "../zig-out/share/locale"; sourceTree = ""; }; A54B0CE82D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIconView.swift; sourceTree = ""; }; A54B0CEA2D0CFB4A00CBEFF8 /* NSImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSImage+Extension.swift"; sourceTree = ""; }; A54B0CEC2D0CFB7300CBEFF8 /* ColorizedGhosttyIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIcon.swift; sourceTree = ""; }; @@ -424,6 +426,7 @@ 29C15B1C2CDC3B2000520DD4 /* bat */, A586167B2B7703CC009BDB1D /* fish */, 55154BDF2B33911F001622DC /* ghostty */, + A546F1132D7B68D7003B11A0 /* locale */, A5985CE52C33060F00C57AD3 /* man */, 9351BE8E2D22937F003B3499 /* nvim */, A5A1F8842A489D6800D1E8BC /* terminfo */, @@ -593,20 +596,21 @@ buildActionMask = 2147483647; files = ( FC9ABA9C2D0F53F80020D4C8 /* bash-completion in Resources */, + 29C15B1D2CDC3B2900520DD4 /* bat in Resources */, + A586167C2B7703CC009BDB1D /* fish in Resources */, + 55154BE02B33911F001622DC /* ghostty in Resources */, + A546F1142D7B68D7003B11A0 /* locale in Resources */, + A5985CE62C33060F00C57AD3 /* man in Resources */, + 9351BE8E3D22937F003B3499 /* nvim in Resources */, + A5A1F8852A489D6800D1E8BC /* terminfo in Resources */, + 552964E62B34A9B400030505 /* vim in Resources */, + FC5218FA2D10FFCE004C93E0 /* zsh in Resources */, A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */, A51BFC1E2B2FB5CE00E92F16 /* About.xib in Resources */, A5E112932AF73E6E00C6E0C2 /* ClipboardConfirmation.xib in Resources */, A5CDF1912AAF9A5800513312 /* ConfigurationErrors.xib in Resources */, 857F63812A5E64F200CA4815 /* MainMenu.xib in Resources */, - 29C15B1D2CDC3B2900520DD4 /* bat in Resources */, A596309A2AEE1C6400D64628 /* Terminal.xib in Resources */, - A586167C2B7703CC009BDB1D /* fish in Resources */, - FC5218FA2D10FFCE004C93E0 /* zsh in Resources */, - 55154BE02B33911F001622DC /* ghostty in Resources */, - A5985CE62C33060F00C57AD3 /* man in Resources */, - A5A1F8852A489D6800D1E8BC /* terminfo in Resources */, - 552964E62B34A9B400030505 /* vim in Resources */, - 9351BE8E3D22937F003B3499 /* nvim in Resources */, A5CBD05C2CA0C5C70017A1AE /* QuickTerminal.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme b/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme index 5900042f2..c2e61f1c2 100644 --- a/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme +++ b/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme @@ -33,6 +33,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "zh-Hans" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/src/build/GhosttyI18n.zig b/src/build/GhosttyI18n.zig index b7aa0be11..56848fdc3 100644 --- a/src/build/GhosttyI18n.zig +++ b/src/build/GhosttyI18n.zig @@ -3,13 +3,10 @@ const GhosttyI18n = @This(); const std = @import("std"); const Config = @import("Config.zig"); const gresource = @import("../apprt/gtk/gresource.zig"); +const internal_os = @import("../os/main.zig"); const domain = "com.mitchellh.ghostty"; -const locales = [_][]const u8{ - "zh_CN.UTF-8", -}; - owner: *std.Build, steps: []*std.Build.Step, @@ -23,7 +20,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n { var steps = std.ArrayList(*std.Build.Step).init(b.allocator); defer steps.deinit(); - inline for (locales) |locale| { + inline for (internal_os.i18n.locales) |locale| { const msgfmt = b.addSystemCommand(&.{ "msgfmt", "-o", "-" }); msgfmt.addFileArg(b.path("po/" ++ locale ++ ".po")); @@ -106,7 +103,7 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step { "po/" ++ domain ++ ".pot", ); - inline for (locales) |locale| { + inline for (internal_os.i18n.locales) |locale| { const msgmerge = b.addSystemCommand(&.{ "msgmerge", "-q" }); msgmerge.addFileArg(b.path("po/" ++ locale ++ ".po")); msgmerge.addFileArg(xgettext.captureStdOut()); diff --git a/src/main_c.zig b/src/main_c.zig index 8a66837d3..1b73d7327 100644 --- a/src/main_c.zig +++ b/src/main_c.zig @@ -15,6 +15,7 @@ const build_config = @import("build_config.zig"); const main = @import("main_ghostty.zig"); const state = &@import("global.zig").state; const apprt = @import("apprt.zig"); +const internal_os = @import("os/main.zig"); // Some comptime assertions that our C API depends on. comptime { @@ -88,3 +89,13 @@ export fn ghostty_info() Info { .version_len = build_config.version_string.len, }; } + +/// Translate a string maintained by libghostty into the current +/// application language. This will return the same string (same pointer) +/// if no translation is found, so the pointer must be stable through +/// the function call. +/// +/// This should only be used for singular strings maintained by Ghostty. +export fn ghostty_translate(msgid: [*:0]const u8) [*:0]const u8 { + return internal_os.i18n._(msgid); +} diff --git a/src/os/i18n.zig b/src/os/i18n.zig index c4609bff8..004ae9477 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -3,6 +3,13 @@ const build_config = @import("../build_config.zig"); const log = std.log.scoped(.i18n); +/// Supported locales for the application. This must be kept up to date +/// with the translations available in the `po/` directory; this is used +/// by our build process as well runtime libghostty APIs. +pub const locales = [_][]const u8{ + "zh_CN.UTF-8", +}; + pub const InitError = error{ InvalidResourcesDir, OutOfMemory, From 3c49bc5086681f5bed98067a64fa8edddc9f175c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 09:50:33 -0800 Subject: [PATCH 08/17] os: locale automatically sets LANGUAGE based on macOS preferred --- .../xcshareddata/xcschemes/Ghostty.xcscheme | 1 - src/os/i18n.zig | 26 ++++++- src/os/locale.zig | 71 +++++++++++++++++-- 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme b/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme index c2e61f1c2..5900042f2 100644 --- a/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme +++ b/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme @@ -33,7 +33,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "zh-Hans" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/src/os/i18n.zig b/src/os/i18n.zig index 004ae9477..a9000e18d 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -6,10 +6,22 @@ const log = std.log.scoped(.i18n); /// Supported locales for the application. This must be kept up to date /// with the translations available in the `po/` directory; this is used /// by our build process as well runtime libghostty APIs. -pub const locales = [_][]const u8{ +/// +/// The order also matters. For incomplete locale information (i.e. only +/// a language code available), the first match is used. For example, if +/// we know the user requested `zh` but has no region code, then we'd pick +/// the first locale that matches `zh`. +pub const locales = [_][:0]const u8{ "zh_CN.UTF-8", }; +/// Set for faster membership lookup of locales. +pub const locales_map = map: { + var kvs: [locales.len]struct { []const u8 } = undefined; + for (locales, 0..) |locale, i| kvs[i] = .{locale}; + break :map std.StaticStringMap(void).initComptime(kvs); +}; + pub const InitError = error{ InvalidResourcesDir, OutOfMemory, @@ -40,6 +52,18 @@ pub fn init(resources_dir: []const u8) InitError!void { return error.OutOfMemory; } +/// Finds the closest matching locale for a given language code. +pub fn closestLocaleForLanguage(lang: []const u8) ?[:0]const u8 { + for (locales) |locale| { + const idx = std.mem.indexOfScalar(u8, locale, '_') orelse continue; + if (std.mem.eql(u8, locale[0..idx], lang)) { + return locale; + } + } + + return null; +} + /// Translate a message for the Ghostty domain. pub fn _(msgid: [*:0]const u8) [*:0]const u8 { return dgettext(build_config.bundle_id, msgid); diff --git a/src/os/locale.zig b/src/os/locale.zig index 361f4fe62..e96ab5e3e 100644 --- a/src/os/locale.zig +++ b/src/os/locale.zig @@ -1,10 +1,11 @@ const std = @import("std"); const builtin = @import("builtin"); const assert = std.debug.assert; +const macos = @import("macos"); const objc = @import("objc"); const internal_os = @import("main.zig"); -const log = std.log.scoped(.os); +const log = std.log.scoped(.os_locale); /// Ensure that the locale is set. pub fn ensureLocale(alloc: std.mem.Allocator) !void { @@ -60,7 +61,7 @@ pub fn ensureLocale(alloc: std.mem.Allocator) !void { _ = internal_os.setenv("LANG", "en_US.UTF-8"); log.info("setlocale default result={s}", .{v}); return; - } else log.err("setlocale failed even with the fallback, uncertain results", .{}); + } else log.warn("setlocale failed even with the fallback, uncertain results", .{}); } /// This sets the LANG environment variable based on the macOS system @@ -71,7 +72,7 @@ fn setLangFromCocoa() void { // The classes we're going to need. const NSLocale = objc.getClass("NSLocale") orelse { - log.err("NSLocale class not found. Locale may be incorrect.", .{}); + log.warn("NSLocale class not found. Locale may be incorrect.", .{}); return; }; @@ -92,16 +93,76 @@ fn setLangFromCocoa() void { // Format them into a buffer var buf: [128]u8 = undefined; const env_value = std.fmt.bufPrintZ(&buf, "{s}_{s}.UTF-8", .{ z_lang, z_country }) catch |err| { - log.err("error setting locale from system. err={}", .{err}); + log.warn("error setting locale from system. err={}", .{err}); return; }; log.info("detected system locale={s}", .{env_value}); // Set it onto our environment if (internal_os.setenv("LANG", env_value) < 0) { - log.err("error setting locale env var", .{}); + log.warn("error setting locale env var", .{}); return; } + + // We also want to set our LANGUAGE for translations. We do this using + // NSLocale.preferredLanguages over our system locale since we want to + // match our app's preferred languages. + language: { + const i18n = internal_os.i18n; + + // We need to get our app's preferred languages. These may not + // match the system locale (NSLocale.currentLocale). + const preferred: *macos.foundation.Array = array: { + const ns = NSLocale.msgSend( + objc.Object, + objc.sel("preferredLanguages"), + .{}, + ); + break :array @ptrCast(ns.value); + }; + for (0..preferred.getCount()) |i| { + const str = preferred.getValueAtIndex(macos.foundation.String, i); + const c_str = c_str: { + const raw = str.cstring(&buf, .utf8) orelse { + // I don't think this can happen but if it does then I want + // to know about it if a user has translation issues. + log.warn("failed to convert a preferred language to UTF-8", .{}); + continue; + }; + + // We want to strip at "-" since we only care about the language + // code, not the region code. i.e. "zh-Hans" -> "zh" + const idx = std.mem.indexOfScalar(u8, raw, '-') orelse raw.len; + break :c_str raw[0..idx]; + }; + + // If our preferred language is equal to our system language + // then we can be done, since the locale above we set everything. + if (std.mem.eql(u8, c_str, z_lang)) { + log.debug("preferred language matches system locale={s}", .{c_str}); + break :language; + } + + // Note: there are many improvements that can be made here to make + // this more and more robust. For example, we can try to search for + // the MOST matching supported locale for translations. Right now + // we fall directly back to language code. + log.debug("searching for closest matching locale preferred={s}", .{c_str}); + if (i18n.closestLocaleForLanguage(c_str)) |i18n_locale| { + log.info("setting LANGUAGE to closest matching locale={s}", .{i18n_locale}); + _ = internal_os.setenv("LANGUAGE", i18n_locale); + break :language; + } + } + + // No matches or our preferred languages are empty. As a final + // try we try to match our system locale. + if (i18n.closestLocaleForLanguage(z_lang)) |i18n_locale| { + log.info("setting LANGUAGE to closest matching locale={s}", .{i18n_locale}); + _ = internal_os.setenv("LANGUAGE", i18n_locale); + break :language; + } + } } const LC_ALL: c_int = 6; // from locale.h From be839cb681a2e256ffb65b22bb95bc3b11fbdf50 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 10:30:12 -0800 Subject: [PATCH 09/17] update our gitattributes with new generated files --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitattributes b/.gitattributes index e6f3c2789..7e39ed959 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,5 +5,7 @@ vendor/** linguist-vendored website/** linguist-documentation pkg/breakpad/vendor/** linguist-vendored pkg/cimgui/vendor/** linguist-vendored +pkg/libintl/config.h linguist-generated=true +pkg/libintl/libintl.h linguist-generated=true pkg/simdutf/vendor/** linguist-vendored src/terminal/res/** linguist-vendored From 3ebd5b839f18aa777474c314e23288c64c992794 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 10:33:09 -0800 Subject: [PATCH 10/17] update translating readme --- po/README_TRANSLATORS.md | 10 +++++++--- src/os/i18n.zig | 11 +++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/po/README_TRANSLATORS.md b/po/README_TRANSLATORS.md index 5db0cf12f..3da3f96b2 100644 --- a/po/README_TRANSLATORS.md +++ b/po/README_TRANSLATORS.md @@ -131,14 +131,18 @@ which should be filled in accordingly. You can then add your translations within the newly created translation file. Afterwards, you need to update the list of known locales within Ghostty's -build system. To do so, open `src/build/GhosttyI18n.zig` and find the list -of locales under the `locale` variable, then append the full locale name +build system. To do so, open `src/os/i81n.zig` and find the list +of locales under the `locales` variable, then add the full locale name into the list. +The order matters, so make sure to place your locale in the correct position. +Read the comment above the variable for more details on the order. If you're +unsure, place it at the end of the list. + ```zig const locales = [_][]const u8{ "zh_CN.UTF-8", - // <- Add your locale here + // <- Add your locale here (probably) } ``` diff --git a/src/os/i18n.zig b/src/os/i18n.zig index a9000e18d..15255578a 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -11,6 +11,17 @@ const log = std.log.scoped(.i18n); /// a language code available), the first match is used. For example, if /// we know the user requested `zh` but has no region code, then we'd pick /// the first locale that matches `zh`. +/// +/// For ordering, we prefer: +/// +/// 1. The most common locales first, since there are places in the code +/// where we do linear searches for a locale and we want to minimize +/// the number of iterations for the common case. +/// +/// 2. Alphabetical for otherwise equally common locales. +/// +/// 3. Most preferred locale for a language without a country code. +/// pub const locales = [_][:0]const u8{ "zh_CN.UTF-8", }; From cff092f4c65957ee7c8f327dfd4bff398d88679e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 10:36:31 -0800 Subject: [PATCH 11/17] nix: update hashes --- build.zig.zon.nix | 8 ++++++++ build.zig.zon.txt | 9 +++++---- build.zig.zon2json-lock | 5 +++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/build.zig.zon.nix b/build.zig.zon.nix index 758166de0..f9d237d4d 100644 --- a/build.zig.zon.nix +++ b/build.zig.zon.nix @@ -331,6 +331,14 @@ in hash = "sha256-NUqLRTm1iOcLmOxwhEJz4/J0EwLEw3e8xOgbPRhm98k="; }; } + { + name = "1220f870c853529233ea64a108acaaa81f8d06d7ff4b66c76930be7d78d508aff7a2"; + path = fetchZigArtifact { + name = "gettext"; + url = "https://deps.files.ghostty.org/gettext-0.24.tar.gz"; + hash = "sha256-yRhQPVk9cNr0hE0XWhPYFq+stmfAb7oeydzVACwVGLc="; + }; + } { name = "1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb"; path = fetchZigArtifact { diff --git a/build.zig.zon.txt b/build.zig.zon.txt index 7b3416cda..b6b52ef52 100644 --- a/build.zig.zon.txt +++ b/build.zig.zon.txt @@ -4,6 +4,7 @@ git+https://github.com/zigimg/zigimg#3a667bdb3d7f0955a5a51c8468eac83210c1439e https://codeberg.org/atman/zg/archive/v0.13.2.tar.gz https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz +https://deps.files.ghostty.org/gettext-0.24.tar.gz https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz https://deps.files.ghostty.org/gobject-12208d70ee791d7ef7e16e1c3c9c1127b57f1ed066a24f87d57fc9f730c5dc394b9d.tar.zst https://deps.files.ghostty.org/harfbuzz-1220b8588f106c996af10249bfa092c6fb2f35fbacb1505ef477a0b04a7dd1063122.tar.gz @@ -22,13 +23,13 @@ https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23c https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz https://deps.files.ghostty.org/z2d-12201f0d542e7541cf492a001d4d0d0155c92f58212fbcb0d224e95edeba06b5416a.tar.gz https://deps.files.ghostty.org/zf-1220edc3b8d8bedbb50555947987e5e8e2f93871ca3c8e8d4cc8f1377c15b5dd35e8.tar.gz -https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz -https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz -https://deps.files.ghostty.org/zig_objc-1220e17e64ef0ef561b3e4b9f3a96a2494285f2ec31c097721bf8c8677ec4415c634.tar.gz https://deps.files.ghostty.org/zig-wayland-fbfe3b4ac0b472a27b1f1a67405436c58cbee12d.tar.gz +https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz +https://deps.files.ghostty.org/zig_objc-1220e17e64ef0ef561b3e4b9f3a96a2494285f2ec31c097721bf8c8677ec4415c634.tar.gz +https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz -https://github.com/getsentry/breakpad/archive/b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz https://github.com/GNOME/libxml2/archive/refs/tags/v2.11.5.tar.gz +https://github.com/getsentry/breakpad/archive/b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz https://github.com/mbadolato/iTerm2-Color-Schemes/archive/e21d5ffd19605741d0e3e19d7c5a8c6c25648673.tar.gz https://github.com/mitchellh/glfw/archive/b552c6ec47326b94015feddb36058ea567b87159.tar.gz https://github.com/mitchellh/libxev/archive/8943932a668f338cb2c500f6e1a7396bacd8b55d.tar.gz diff --git a/build.zig.zon2json-lock b/build.zig.zon2json-lock index da53e9733..463bba939 100644 --- a/build.zig.zon2json-lock +++ b/build.zig.zon2json-lock @@ -154,6 +154,11 @@ "url": "https://deps.files.ghostty.org/highway-12205c83b8311a24b1d5ae6d21640df04f4b0726e314337c043cde1432758cbe165b.tar.gz", "hash": "sha256-NUqLRTm1iOcLmOxwhEJz4/J0EwLEw3e8xOgbPRhm98k=" }, + "1220f870c853529233ea64a108acaaa81f8d06d7ff4b66c76930be7d78d508aff7a2": { + "name": "gettext", + "url": "https://deps.files.ghostty.org/gettext-0.24.tar.gz", + "hash": "sha256-yRhQPVk9cNr0hE0XWhPYFq+stmfAb7oeydzVACwVGLc=" + }, "1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb": { "name": "oniguruma", "url": "https://deps.files.ghostty.org/oniguruma-1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb.tar.gz", From c7681e8fd7a2eadc0cb38f4ae9a8ddd03b05ffa7 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 10:41:22 -0800 Subject: [PATCH 12/17] apprt/gtk: use the new global i18n API --- src/apprt/gtk/App.zig | 10 ++++------ src/apprt/gtk/Surface.zig | 2 +- src/apprt/gtk/Window.zig | 2 +- src/apprt/gtk/i18n.zig | 37 ------------------------------------- src/os/i18n.zig | 9 +++++++++ 5 files changed, 15 insertions(+), 45 deletions(-) delete mode 100644 src/apprt/gtk/i18n.zig diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index 84df35606..9893f1ee9 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -40,7 +40,6 @@ const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig"); const CloseDialog = @import("CloseDialog.zig"); const Split = @import("Split.zig"); const c = @import("c.zig").c; -const i18n = @import("i18n.zig"); const version = @import("version.zig"); const inspector = @import("inspector.zig"); const key = @import("key.zig"); @@ -101,11 +100,6 @@ quit_timer: union(enum) { pub fn init(core_app: *CoreApp, opts: Options) !App { _ = opts; - // This can technically be placed *anywhere* because we don't have any - // localized log messages. It just has to be placed before any localized - // widgets are drawn. - try i18n.init(core_app.alloc); - // Log our GTK version log.info("GTK version build={d}.{d}.{d} runtime={d}.{d}.{d}", .{ c.GTK_MAJOR_VERSION, @@ -124,6 +118,10 @@ pub fn init(core_app: *CoreApp, opts: Options) !App { c.adw_get_micro_version(), }); + // Set gettext global domain to be our app so that our unqualified + // translations map to our translations. + try internal_os.i18n.initGlobalDomain(); + // Load our configuration var config = try Config.load(core_app.alloc); errdefer config.deinit(); diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index ae3ca12d6..23abccc20 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -16,6 +16,7 @@ const build_options = @import("build_options"); const configpkg = @import("../../config.zig"); const apprt = @import("../../apprt.zig"); const font = @import("../../font/main.zig"); +const i18n = @import("../../os/main.zig").i18n; const input = @import("../../input.zig"); const renderer = @import("../../renderer.zig"); const terminal = @import("../../terminal/main.zig"); @@ -36,7 +37,6 @@ const gtk_key = @import("key.zig"); const c = @import("c.zig").c; const Builder = @import("Builder.zig"); const adwaita = @import("adwaita.zig"); -const i18n = @import("i18n.zig"); const log = std.log.scoped(.gtk_surface); diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 0e0f71662..8c3e135c5 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -18,6 +18,7 @@ const gtk = @import("gtk"); const build_config = @import("../../build_config.zig"); const configpkg = @import("../../config.zig"); const font = @import("../../font/main.zig"); +const i18n = @import("../../os/main.zig").i18n; const input = @import("../../input.zig"); const CoreSurface = @import("../../Surface.zig"); @@ -34,7 +35,6 @@ const HeaderBar = @import("headerbar.zig"); const CloseDialog = @import("CloseDialog.zig"); const version = @import("version.zig"); const winproto = @import("winproto.zig"); -const i18n = @import("i18n.zig"); const log = std.log.scoped(.gtk); diff --git a/src/apprt/gtk/i18n.zig b/src/apprt/gtk/i18n.zig deleted file mode 100644 index 630d150a6..000000000 --- a/src/apprt/gtk/i18n.zig +++ /dev/null @@ -1,37 +0,0 @@ -//! I18n support for the GTK frontend based on gettext/libintl -//! -//! This is normally built into the C standard library for the *vast* majority -//! of users who use glibc, but for musl users we fall back to the `gettext-tiny` -//! stub implementation which provides all of the necessary interfaces. -//! Musl users who do want to use localization should know what they need to do. - -const std = @import("std"); -const global = &@import("../../global.zig").state; -const build_config = @import("../../build_config.zig"); - -const log = std.log.scoped(.gtk_i18n); - -pub fn init(alloc: std.mem.Allocator) !void { - const resources_dir = global.resources_dir orelse { - log.warn("resource dir not found; not localizing", .{}); - return; - }; - const share_dir = std.fs.path.dirname(resources_dir) orelse { - log.warn("resource dir not placed in a share/ directory; not localizing", .{}); - return; - }; - - const locale_dir = try std.fs.path.joinZ(alloc, &.{ share_dir, "locale" }); - defer alloc.free(locale_dir); - - // The only way these calls can fail is if we're out of memory - _ = bindtextdomain(build_config.bundle_id, locale_dir.ptr) orelse return error.OutOfMemory; - _ = textdomain(build_config.bundle_id) orelse return error.OutOfMemory; -} - -// Manually include function definitions for the gettext functions -// as libintl.h isn't always easily available (e.g. in musl) -extern fn bindtextdomain(domainname: [*:0]const u8, dirname: [*:0]const u8) ?[*:0]const u8; -extern fn textdomain(domainname: [*:0]const u8) ?[*:0]const u8; -pub extern fn gettext(msgid: [*:0]const u8) [*:0]const u8; -pub const _ = gettext; diff --git a/src/os/i18n.zig b/src/os/i18n.zig index 15255578a..8a4efdc73 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -63,6 +63,15 @@ pub fn init(resources_dir: []const u8) InitError!void { return error.OutOfMemory; } +/// Set the global gettext domain to our bundle ID, allowing unqualified +/// `gettext` (`_`) calls to look up translations for our application. +/// +/// This should only be called for apprts that are fully owning the +/// Ghostty application. This should not be called for libghostty users. +pub fn initGlobalDomain() error{OutOfMemory}!void { + _ = textdomain(build_config.bundle_id) orelse return error.OutOfMemory; +} + /// Finds the closest matching locale for a given language code. pub fn closestLocaleForLanguage(lang: []const u8) ?[:0]const u8 { for (locales) |locale| { From e8a988f6d34d26e23dbbcec49596b607dec034ce Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 10:47:59 -0800 Subject: [PATCH 13/17] os: i18n unsupported on windows --- src/os/i18n.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/os/i18n.zig b/src/os/i18n.zig index 8a4efdc73..4c136db4f 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const build_config = @import("../build_config.zig"); const log = std.log.scoped(.i18n); @@ -47,6 +48,9 @@ pub const InitError = error{ /// want to set the domain for the entire application since this is also /// used by libghostty. pub fn init(resources_dir: []const u8) InitError!void { + // i18n is unsupported on Windows + if (builtin.os.tag == .windows) return; + // Our resources dir is always nested below the share dir that // is standard for translations. const share_dir = std.fs.path.dirname(resources_dir) orelse From 79a9ddf66fcfd248ae484f0443f9340b4fa85f02 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 10:54:14 -0800 Subject: [PATCH 14/17] build: pure libghostty builds need to build translations --- build.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/build.zig b/build.zig index f07918441..f2fa9c233 100644 --- a/build.zig +++ b/build.zig @@ -60,6 +60,7 @@ pub fn build(b: *std.Build) !void { // The xcframework build always installs resources because our // macOS xcode project contains references to them. resources.install(); + i18n.install(); // If we aren't emitting docs we need to emit a placeholder so // our macOS xcodeproject builds. From da731e6caa37f10006df379916986807e08a92ce Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 11:16:43 -0800 Subject: [PATCH 15/17] typo i81n -> i18n --- po/README_TRANSLATORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/README_TRANSLATORS.md b/po/README_TRANSLATORS.md index 3da3f96b2..ca1e45faa 100644 --- a/po/README_TRANSLATORS.md +++ b/po/README_TRANSLATORS.md @@ -131,7 +131,7 @@ which should be filled in accordingly. You can then add your translations within the newly created translation file. Afterwards, you need to update the list of known locales within Ghostty's -build system. To do so, open `src/os/i81n.zig` and find the list +build system. To do so, open `src/os/i18n.zig` and find the list of locales under the `locales` variable, then add the full locale name into the list. From 7eddf9826911f69183cdf608957d7985826330cd Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 11:31:27 -0800 Subject: [PATCH 16/17] Fix typos --- src/os/i18n.zig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/os/i18n.zig b/src/os/i18n.zig index 4c136db4f..6ae8683fd 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -10,7 +10,7 @@ const log = std.log.scoped(.i18n); /// /// The order also matters. For incomplete locale information (i.e. only /// a language code available), the first match is used. For example, if -/// we know the user requested `zh` but has no region code, then we'd pick +/// we know the user requested `zh` but has no script code, then we'd pick /// the first locale that matches `zh`. /// /// For ordering, we prefer: @@ -97,5 +97,4 @@ pub fn _(msgid: [*:0]const u8) [*:0]const u8 { // as libintl.h isn't always easily available (e.g. in musl) extern fn bindtextdomain(domainname: [*:0]const u8, dirname: [*:0]const u8) ?[*:0]const u8; extern fn textdomain(domainname: [*:0]const u8) ?[*:0]const u8; -extern fn gettext(msgid: [*:0]const u8) [*:0]const u8; extern fn dgettext(domainname: [*:0]const u8, msgid: [*:0]const u8) [*:0]const u8; From dcb8440b52695b391d770908207427c506205cc5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 7 Mar 2025 13:21:43 -0800 Subject: [PATCH 17/17] os: remove the preferredLanguages lookup --- src/apprt/gtk/CloseDialog.zig | 2 +- src/os/i18n.zig | 26 ++++++++------- src/os/locale.zig | 61 +---------------------------------- 3 files changed, 16 insertions(+), 73 deletions(-) diff --git a/src/apprt/gtk/CloseDialog.zig b/src/apprt/gtk/CloseDialog.zig index 2077f9b76..da6a45a36 100644 --- a/src/apprt/gtk/CloseDialog.zig +++ b/src/apprt/gtk/CloseDialog.zig @@ -6,12 +6,12 @@ const gio = @import("gio"); const adw = @import("adw"); const gtk = @import("gtk"); +const i18n = @import("../../os/main.zig").i18n; const App = @import("App.zig"); const Window = @import("Window.zig"); const Tab = @import("Tab.zig"); const Surface = @import("Surface.zig"); const adwaita = @import("adwaita.zig"); -const i18n = @import("i18n.zig"); const log = std.log.scoped(.close_dialog); diff --git a/src/os/i18n.zig b/src/os/i18n.zig index 6ae8683fd..69b222da5 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -76,23 +76,25 @@ pub fn initGlobalDomain() error{OutOfMemory}!void { _ = textdomain(build_config.bundle_id) orelse return error.OutOfMemory; } -/// Finds the closest matching locale for a given language code. -pub fn closestLocaleForLanguage(lang: []const u8) ?[:0]const u8 { - for (locales) |locale| { - const idx = std.mem.indexOfScalar(u8, locale, '_') orelse continue; - if (std.mem.eql(u8, locale[0..idx], lang)) { - return locale; - } - } - - return null; -} - /// Translate a message for the Ghostty domain. pub fn _(msgid: [*:0]const u8) [*:0]const u8 { return dgettext(build_config.bundle_id, msgid); } +/// This can be called at any point a compile-time-known locale is +/// available. This will use comptime to verify the locale is supported. +pub fn staticLocale(comptime v: [*:0]const u8) [*:0]const u8 { + comptime { + for (locales) |locale| { + if (std.mem.eql(u8, locale, v)) { + return locale; + } + } + + @compileError("unsupported locale"); + } +} + // Manually include function definitions for the gettext functions // as libintl.h isn't always easily available (e.g. in musl) extern fn bindtextdomain(domainname: [*:0]const u8, dirname: [*:0]const u8) ?[*:0]const u8; diff --git a/src/os/locale.zig b/src/os/locale.zig index e96ab5e3e..840687143 100644 --- a/src/os/locale.zig +++ b/src/os/locale.zig @@ -4,6 +4,7 @@ const assert = std.debug.assert; const macos = @import("macos"); const objc = @import("objc"); const internal_os = @import("main.zig"); +const i18n = internal_os.i18n; const log = std.log.scoped(.os_locale); @@ -103,66 +104,6 @@ fn setLangFromCocoa() void { log.warn("error setting locale env var", .{}); return; } - - // We also want to set our LANGUAGE for translations. We do this using - // NSLocale.preferredLanguages over our system locale since we want to - // match our app's preferred languages. - language: { - const i18n = internal_os.i18n; - - // We need to get our app's preferred languages. These may not - // match the system locale (NSLocale.currentLocale). - const preferred: *macos.foundation.Array = array: { - const ns = NSLocale.msgSend( - objc.Object, - objc.sel("preferredLanguages"), - .{}, - ); - break :array @ptrCast(ns.value); - }; - for (0..preferred.getCount()) |i| { - const str = preferred.getValueAtIndex(macos.foundation.String, i); - const c_str = c_str: { - const raw = str.cstring(&buf, .utf8) orelse { - // I don't think this can happen but if it does then I want - // to know about it if a user has translation issues. - log.warn("failed to convert a preferred language to UTF-8", .{}); - continue; - }; - - // We want to strip at "-" since we only care about the language - // code, not the region code. i.e. "zh-Hans" -> "zh" - const idx = std.mem.indexOfScalar(u8, raw, '-') orelse raw.len; - break :c_str raw[0..idx]; - }; - - // If our preferred language is equal to our system language - // then we can be done, since the locale above we set everything. - if (std.mem.eql(u8, c_str, z_lang)) { - log.debug("preferred language matches system locale={s}", .{c_str}); - break :language; - } - - // Note: there are many improvements that can be made here to make - // this more and more robust. For example, we can try to search for - // the MOST matching supported locale for translations. Right now - // we fall directly back to language code. - log.debug("searching for closest matching locale preferred={s}", .{c_str}); - if (i18n.closestLocaleForLanguage(c_str)) |i18n_locale| { - log.info("setting LANGUAGE to closest matching locale={s}", .{i18n_locale}); - _ = internal_os.setenv("LANGUAGE", i18n_locale); - break :language; - } - } - - // No matches or our preferred languages are empty. As a final - // try we try to match our system locale. - if (i18n.closestLocaleForLanguage(z_lang)) |i18n_locale| { - log.info("setting LANGUAGE to closest matching locale={s}", .{i18n_locale}); - _ = internal_os.setenv("LANGUAGE", i18n_locale); - break :language; - } - } } const LC_ALL: c_int = 6; // from locale.h