bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

localename: Add support for Haiku's per-thread locales


From: Bruno Haible
Subject: localename: Add support for Haiku's per-thread locales
Date: Wed, 05 Apr 2023 15:40:52 +0200

In 2022, Haiku got support for per-thread locales (POSIX functions
uselocale, newlocale, duplocale, freelocale).

Gnulib needs support for this in the 'localename' module (so that
GNU gettext will work when a per-thread locale is installed).

This patch does it. It is pretty ugly, though.


2023-04-05  Bruno Haible  <bruno@clisp.org>

        localename: Add support for Haiku's per-thread locales.
        * lib/localename.c: Include <dlfcn.h>.
        (gl_locale_name_thread_unsafe): Add special code for Haiku.

diff --git a/lib/localename.c b/lib/localename.c
index 8fe90e0bf2..3c1dc67c14 100644
--- a/lib/localename.c
+++ b/lib/localename.c
@@ -59,6 +59,9 @@ extern char * getlocalename_l(int, locale_t);
 # if HAVE_NAMELESS_LOCALES
 #  include "localename-table.h"
 # endif
+# if defined __HAIKU__
+#  include <dlfcn.h>
+# endif
 #endif
 
 #if HAVE_CFPREFERENCESCOPYAPPVALUE
@@ -3203,6 +3206,68 @@ gl_locale_name_thread_unsafe (int category, _GL_UNUSED 
const char *categoryname)
         };
         return ((struct __locale_t *) thread_locale)->categories[category];
 #   endif
+#  elif defined __HAIKU__
+        /* Since 2022, Haiku has per-thread locales.  locale_t is 'void *',
+           but in fact a 'LocaleBackendData *'.  */
+        struct LocaleBackendData {
+          int magic;
+          void /*BPrivate::Libroot::LocaleBackend*/ *backend;
+          void /*BPrivate::Libroot::LocaleDataBridge*/ *databridge;
+        };
+        void *thread_locale_backend =
+          ((struct LocaleBackendData *) thread_locale)->backend;
+        if (thread_locale_backend != NULL)
+          {
+            /* The only existing concrete subclass of
+               BPrivate::Libroot::LocaleBackend is
+               BPrivate::Libroot::ICULocaleBackend.
+               Invoke the (non-virtual) method
+               BPrivate::Libroot::ICULocaleBackend::_QueryLocale on it.
+               This method is located in a separate shared library,
+               libroot-addon-icu.so.  */
+            static void * volatile querylocale_method /* = NULL */;
+            static int volatile querylocale_found /* = 0 */;
+            /* Attempt to open this shared library, the first time we get
+               here.  */
+            if (querylocale_found == 0)
+              {
+                void *handle =
+                  dlopen ("/boot/system/lib/libroot-addon-icu.so", 0);
+                if (handle != NULL)
+                  {
+                    void *sym =
+                      dlsym (handle, 
"_ZN8BPrivate7Libroot16ICULocaleBackend12_QueryLocaleEi");
+                    if (sym != NULL)
+                      {
+                        querylocale_method = sym;
+                        querylocale_found = 1;
+                      }
+                    else
+                      /* Could not find the symbol.  */
+                      querylocale_found = -1;
+                  }
+                else
+                  /* Could not open the separate shared library.  */
+                  querylocale_found = -1;
+              }
+            if (querylocale_found > 0)
+              {
+                /* The _QueryLocale method is a non-static C++ method with
+                   parameters (int category) and return type 'const char *'.
+                   See
+                     haiku/headers/private/libroot/locale/ICULocaleBackend.h
+                     haiku/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp
+                   This is the same as a C function with parameters
+                     (BPrivate::Libroot::LocaleBackend* this, int category)
+                   and return type 'const char *'.  Invoke it.  */
+                const char * (*querylocale_func) (void *, int) =
+                  (const char * (*) (void *, int)) querylocale_method;
+                return querylocale_func (thread_locale_backend, category);
+              }
+          }
+        else
+          /* It's the "C" or "POSIX" locale.  */
+          return "C";
 #  elif defined __ANDROID__
         return MB_CUR_MAX == 4 ? "C.UTF-8" : "C";
 #  endif






reply via email to

[Prev in Thread] Current Thread [Next in Thread]