(root)/
coreutils-9.4/
gnulib-tests/
test-nl_langinfo2.c
       1  /* Test of nl_langinfo replacement.
       2     Copyright (C) 2023 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation, either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Bruno Haible <bruno@clisp.org>, 2023.  */
      18  
      19  #include <config.h>
      20  
      21  #include <langinfo.h>
      22  
      23  #include <locale.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  
      27  #include "c-strcase.h"
      28  #include "c-strcasestr.h"
      29  #include "macros.h"
      30  
      31  int
      32  main (int argc, char *argv[])
      33  {
      34  #if HAVE_WORKING_USELOCALE
      35    /* Check that nl_langinfo() uses the per-thread locale.  */
      36    int pass;
      37    bool skipped_all = true;
      38  
      39    /* Extract a few items from the C locale.  */
      40    /* nl_langinfo items of the LC_CTYPE category */
      41    const char *c_CODESET = nl_langinfo (CODESET);
      42    /* nl_langinfo items of the LC_NUMERIC category */
      43    const char *c_RADIXCHAR = nl_langinfo (RADIXCHAR);
      44    /* nl_langinfo items of the LC_TIME category */
      45    const char *c_T_FMT_AMPM = nl_langinfo (T_FMT_AMPM);
      46    const char *c_AM_STR = nl_langinfo (AM_STR);
      47    const char *c_PM_STR = nl_langinfo (PM_STR);
      48    /* nl_langinfo items of the LC_MONETARY category */
      49    const char *c_CRNCYSTR = nl_langinfo (CRNCYSTR);
      50    /* nl_langinfo items of the LC_MESSAGES category */
      51    const char *c_YESEXPR = nl_langinfo (YESEXPR);
      52  
      53    /* Sanity checks.  */
      54    (void) c_CODESET;
      55    ASSERT (strcmp (c_RADIXCHAR, ".") == 0);
      56    ASSERT (strlen (c_T_FMT_AMPM) > 0);
      57    ASSERT (strlen (c_AM_STR) > 0);
      58    ASSERT (strlen (c_PM_STR) > 0);
      59    ASSERT (strlen (c_CRNCYSTR) <= 1); /* "-", "+", ".", or "" */
      60    ASSERT (c_strcasestr (c_YESEXPR, "y" /* from "yes" */) != NULL);
      61  
      62    for (pass = 1; pass <= 2; pass++)
      63      {
      64        /* pass    locale
      65            1        traditional French locale
      66            2        French UTF-8 locale
      67         */
      68        const char *fr_locale_name =
      69          getenv (pass == 1 ? "LOCALE_FR" : "LOCALE_FR_UTF8");
      70        if (strcmp (fr_locale_name, "none") != 0)
      71          {
      72            /* Use a per-thread locale.  */
      73            locale_t fr_locale = newlocale (LC_ALL_MASK, fr_locale_name, NULL);
      74            if (fr_locale != NULL)
      75              {
      76                uselocale (fr_locale);
      77  
      78                /* Extract a few items from the current locale, and check the
      79                   values.  */
      80  
      81                /* nl_langinfo items of the LC_CTYPE category */
      82                const char *fr_CODESET = nl_langinfo (CODESET);
      83                if (pass == 1)
      84                  ASSERT (strstr (fr_CODESET, "8859") != NULL);
      85                else if (pass == 2)
      86                  ASSERT (c_strcasecmp (fr_CODESET, "UTF-8") == 0
      87                          || c_strcasecmp (fr_CODESET, "UTF8") == 0);
      88  
      89                /* In musl libc, locales differ at most in the LC_MESSAGES
      90                   category.  */
      91                #if !defined MUSL_LIBC
      92  
      93                /* nl_langinfo items of the LC_NUMERIC category */
      94                const char *fr_RADIXCHAR = nl_langinfo (RADIXCHAR);
      95                ASSERT (strcmp (fr_RADIXCHAR, ",") == 0);
      96  
      97                /* nl_langinfo items of the LC_TIME category */
      98                /* macOS and Solaris 11 don't get the LC_TIME values right.
      99                   Poor.  */
     100                #if !((defined __APPLE__ && defined __MACH__) || defined __sun)
     101                const char *fr_T_FMT_AMPM = nl_langinfo (T_FMT_AMPM);
     102                const char *fr_AM_STR = nl_langinfo (AM_STR);
     103                const char *fr_PM_STR = nl_langinfo (PM_STR);
     104                ASSERT (strlen (fr_T_FMT_AMPM) == 0
     105                        || strcmp (fr_T_FMT_AMPM, "%I:%M:%S") == 0);
     106                ASSERT (strlen (fr_AM_STR) == 0);
     107                ASSERT (strlen (fr_PM_STR) == 0);
     108                #endif
     109  
     110                /* nl_langinfo items of the LC_MONETARY category */
     111                /* macOS doesn't get the EUR currency symbol or abbreviation
     112                   right.  Very poor.  */
     113                #if !(defined __APPLE__ && defined __MACH__)
     114                const char *fr_CRNCYSTR = nl_langinfo (CRNCYSTR);
     115                if (pass == 2)
     116                  ASSERT (strlen (fr_CRNCYSTR) >= 1
     117                          && strcmp (fr_CRNCYSTR + 1, "") == 0);
     118                #endif
     119  
     120                #endif
     121  
     122                /* nl_langinfo items of the LC_MESSAGES category */
     123                /* In musl libc, this works only if the package 'musl-locales' is
     124                   installed.  */
     125                #if !defined MUSL_LIBC
     126                const char *fr_YESEXPR = nl_langinfo (YESEXPR);
     127                ASSERT (c_strcasestr (fr_YESEXPR, "o" /* from "oui" */) != NULL);
     128                #endif
     129  
     130                skipped_all = false;
     131              }
     132          }
     133      }
     134  
     135    if (skipped_all)
     136      {
     137        fputs ("Skipping test: French locale is not installed\n", stderr);
     138        return 77;
     139      }
     140  
     141    return 0;
     142  #else
     143    fputs ("Skipping test: uselocale() not available\n", stderr);
     144    return 77;
     145  #endif
     146  }