| /* Multithread-safety test for nl_langinfo(). |
| Copyright (C) 2019-2020 Free Software Foundation, Inc. |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 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 General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| |
| /* Written by Bruno Haible <bruno@clisp.org>, 2019. */ |
| |
| #include <config.h> |
| |
| #if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS |
| |
| /* Specification. */ |
| #include <langinfo.h> |
| |
| #include <locale.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| |
| #include "glthread/thread.h" |
| |
| |
| /* Some common locale names. */ |
| |
| #if defined _WIN32 && !defined __CYGWIN__ |
| # define ENGLISH "English_United States" |
| # define FRENCH "French_France" |
| # define GERMAN "German_Germany" |
| # define ENCODING ".1252" |
| #else |
| # define ENGLISH "en_US" |
| # define FRENCH "fr_FR" |
| # define GERMAN "de_DE" |
| # if defined __sgi |
| # define ENCODING ".ISO8859-15" |
| # elif defined __hpux |
| # define ENCODING ".utf8" |
| # else |
| # define ENCODING ".UTF-8" |
| # endif |
| #endif |
| |
| static const char LOCALE1[] = ENGLISH ENCODING; |
| static const char LOCALE2[] = FRENCH ENCODING; |
| static const char LOCALE3[] = GERMAN ENCODING; |
| |
| static char *expected1; |
| |
| static void * |
| thread1_func (void *arg) |
| { |
| for (;;) |
| { |
| const char *value = nl_langinfo (CODESET); |
| if (strcmp (expected1, value) != 0) |
| { |
| fprintf (stderr, "thread1 disturbed by threadN!\n"); fflush (stderr); |
| abort (); |
| } |
| } |
| |
| /*NOTREACHED*/ |
| return NULL; |
| } |
| |
| static char *expected2; |
| |
| static void * |
| thread2_func (void *arg) |
| { |
| for (;;) |
| { |
| const char *value = nl_langinfo (PM_STR); |
| if (strcmp (expected2, value) != 0) |
| { |
| fprintf (stderr, "thread2 disturbed by threadN!\n"); fflush (stderr); |
| abort (); |
| } |
| } |
| |
| /*NOTREACHED*/ |
| return NULL; |
| } |
| |
| static char *expected3; |
| |
| static void * |
| thread3_func (void *arg) |
| { |
| for (;;) |
| { |
| const char *value = nl_langinfo (DAY_2); |
| if (strcmp (expected3, value) != 0) |
| { |
| fprintf (stderr, "thread3 disturbed by threadN!\n"); fflush (stderr); |
| abort (); |
| } |
| } |
| |
| /*NOTREACHED*/ |
| return NULL; |
| } |
| |
| static char *expected4; |
| |
| static void * |
| thread4_func (void *arg) |
| { |
| for (;;) |
| { |
| const char *value = nl_langinfo (ALTMON_2); |
| if (strcmp (expected4, value) != 0) |
| { |
| fprintf (stderr, "thread4 disturbed by threadN!\n"); fflush (stderr); |
| abort (); |
| } |
| } |
| |
| /*NOTREACHED*/ |
| return NULL; |
| } |
| |
| static char *expected5; |
| |
| static void * |
| thread5_func (void *arg) |
| { |
| for (;;) |
| { |
| const char *value = nl_langinfo (CRNCYSTR); |
| if (strcmp (expected5, value) != 0) |
| { |
| fprintf (stderr, "thread5 disturbed by threadN!\n"); fflush (stderr); |
| abort (); |
| } |
| } |
| |
| /*NOTREACHED*/ |
| return NULL; |
| } |
| |
| static char *expected6; |
| |
| static void * |
| thread6_func (void *arg) |
| { |
| for (;;) |
| { |
| const char *value = nl_langinfo (RADIXCHAR); |
| if (strcmp (expected6, value) != 0) |
| { |
| fprintf (stderr, "thread6 disturbed by threadN!\n"); fflush (stderr); |
| abort (); |
| } |
| } |
| |
| /*NOTREACHED*/ |
| return NULL; |
| } |
| |
| static void * |
| threadN_func (void *arg) |
| { |
| for (;;) |
| { |
| nl_langinfo (CODESET); /* LC_CTYPE */ /* locale charmap */ |
| nl_langinfo (AM_STR); /* LC_TIME */ /* locale -k am_pm */ |
| nl_langinfo (PM_STR); /* LC_TIME */ /* locale -k am_pm */ |
| nl_langinfo (DAY_2); /* LC_TIME */ /* locale -k day */ |
| nl_langinfo (DAY_5); /* LC_TIME */ /* locale -k day */ |
| nl_langinfo (ALTMON_2); /* LC_TIME */ /* locale -k alt_mon */ |
| nl_langinfo (ALTMON_9); /* LC_TIME */ /* locale -k alt_mon */ |
| nl_langinfo (CRNCYSTR); /* LC_MONETARY */ /* locale -k currency_symbol */ |
| nl_langinfo (RADIXCHAR); /* LC_NUMERIC */ /* locale -k decimal_point */ |
| nl_langinfo (THOUSEP); /* LC_NUMERIC */ /* locale -k thousands_sep */ |
| } |
| |
| /*NOTREACHED*/ |
| return NULL; |
| } |
| |
| int |
| main (int argc, char *argv[]) |
| { |
| if (setlocale (LC_ALL, LOCALE1) == NULL) |
| { |
| fprintf (stderr, "Skipping test: LOCALE1 not recognized\n"); |
| return 77; |
| } |
| if (setlocale (LC_MONETARY, LOCALE2) == NULL) |
| { |
| fprintf (stderr, "Skipping test: LOCALE2 not recognized\n"); |
| return 77; |
| } |
| if (setlocale (LC_NUMERIC, LOCALE3) == NULL) |
| { |
| fprintf (stderr, "Skipping test: LOCALE3 not recognized\n"); |
| return 77; |
| } |
| |
| expected1 = strdup (nl_langinfo (CODESET)); |
| expected2 = strdup (nl_langinfo (PM_STR)); |
| expected3 = strdup (nl_langinfo (DAY_2)); |
| expected4 = strdup (nl_langinfo (ALTMON_2)); |
| expected5 = strdup (nl_langinfo (CRNCYSTR)); |
| expected6 = strdup (nl_langinfo (RADIXCHAR)); |
| |
| /* Create the checker threads. */ |
| gl_thread_create (thread1_func, NULL); |
| gl_thread_create (thread2_func, NULL); |
| gl_thread_create (thread3_func, NULL); |
| gl_thread_create (thread4_func, NULL); |
| gl_thread_create (thread5_func, NULL); |
| gl_thread_create (thread6_func, NULL); |
| /* Create the disturber thread. */ |
| gl_thread_create (threadN_func, NULL); |
| |
| /* Let them run for 2 seconds. */ |
| { |
| struct timespec duration; |
| duration.tv_sec = (argc > 1 ? atoi (argv[1]) : 2); |
| duration.tv_nsec = 0; |
| |
| nanosleep (&duration, NULL); |
| } |
| |
| return 0; |
| } |
| |
| #else |
| |
| /* No multithreading available. */ |
| |
| #include <stdio.h> |
| |
| int |
| main () |
| { |
| fputs ("Skipping test: multithreading not enabled\n", stderr); |
| return 77; |
| } |
| |
| #endif |