1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2014 Garrett D'Amore <garrett@damore.org> 14 */ 15 16 /* 17 * This program tests that newlocale and uselocale work properly in 18 * multi-threaded programs. In order for it to work, it requires that 19 * some additional locales be installed. 20 */ 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <locale.h> 26 #include <libintl.h> 27 #include <langinfo.h> 28 #include <nl_types.h> 29 #include <err.h> 30 #include <unistd.h> 31 #include <pthread.h> 32 33 int debug = 0; 34 35 /* 36 * Note that on some platforms, different symbols are used. For example, 37 * MacOS Mavericks uses "Eu" for Euro symbol, instead of €. If the locale 38 * data changes, then this program will need to update to reflect that. 39 */ 40 struct ldata { 41 const char *locale; 42 const char *day1; 43 const char *cursym; 44 } ldata[] = { 45 { "C", "Sunday", "" }, 46 { "en_US.UTF-8", "Sunday", "$" }, 47 { "de_DE.UTF-8", "Sonntag", "€" }, 48 { "ru_RU.UTF-8", "воскресенье", "руб." }, 49 { "ja_JP.UTF-8", "日曜日", "¥" }, 50 }; 51 52 #define NUM_LDATA 5 53 #define NUMTHR 20 54 #define NUMITR 200 55 56 static void 57 test_start(const char *testName, const char *format, ...) 58 { 59 va_list args; 60 61 (void) printf("TEST STARTING %s: ", testName); 62 63 va_start(args, format); 64 (void) vprintf(format, args); 65 va_end(args); 66 (void) fflush(stdout); 67 } 68 69 static void 70 test_failed(const char *testName, const char *format, ...) 71 { 72 va_list args; 73 74 (void) printf("TEST FAILED %s: ", testName); 75 76 va_start(args, format); 77 (void) vprintf(format, args); 78 va_end(args); 79 80 (void) exit(-1); 81 } 82 83 static void 84 test_passed(const char *testName) 85 { 86 (void) printf("TEST PASS: %s\n", testName); 87 (void) fflush(stdout); 88 } 89 90 void * 91 testlocale_thr(void *ptr) 92 { 93 locale_t cloc, loc; 94 struct lconv *lc; 95 char *day; 96 char *tname = ptr; 97 98 for (int i = 0; i < NUMITR; i++) { 99 struct ldata *l = &ldata[i % NUM_LDATA]; 100 cloc = uselocale(NULL); 101 102 loc = newlocale(LC_ALL_MASK, l->locale, NULL); 103 if (loc == NULL) { 104 test_failed("newlocale %s failed", l->locale); 105 } 106 day = nl_langinfo_l(DAY_1, loc); 107 if (strcmp(day, l->day1) != 0) { 108 test_failed(tname, "newlocale data mismatch (%s != %s)", 109 day, l->day1); 110 } 111 if (debug) 112 (void) printf("DAY1: %s\n", day); 113 114 day = nl_langinfo(DAY_1); 115 if (strcmp(day, "Sunday") != 0) { 116 test_failed(tname, "C locale day wrong %s != Sunday", 117 day); 118 } 119 lc = localeconv(); 120 if (strcmp(lc->currency_symbol, "") != 0) { 121 test_failed(tname, "C cursym mismatch (%s != %s)", 122 lc->currency_symbol, ""); 123 } 124 125 /* we sleep a random bit to mix it up */ 126 (void) usleep(rand() % 10); 127 128 (void) uselocale(loc); 129 day = nl_langinfo(DAY_1); 130 if (strcmp(day, l->day1) != 0) { 131 test_failed(tname, "uselocale data mismatch (%s != %s)", 132 day, l->day1); 133 } 134 135 lc = localeconv(); 136 if (strcmp(lc->currency_symbol, l->cursym) != 0) { 137 test_failed(tname, "uselocal cursym %s != %s", 138 lc->currency_symbol, l->cursym); 139 } 140 if (debug) 141 (void) printf("CSYM: %s\n", lc->currency_symbol); 142 143 /* we sleep a random bit to mix it up */ 144 (void) usleep(rand() % 10); 145 146 if (uselocale(cloc) != loc) { 147 test_failed(tname, "revert old locale mismatch"); 148 } 149 freelocale(loc); 150 if (uselocale(LC_GLOBAL_LOCALE) != cloc) { 151 test_failed(tname, "revert GLOBAL_LOCALE mismatch"); 152 } 153 } 154 return (NULL); 155 } 156 157 158 void 159 testlocale(void) 160 { 161 char *tname = "newlocale/uselocale"; 162 pthread_t tid[NUMTHR]; 163 164 test_start(tname, "running %d threads %d iterations\n", NUMTHR, NUMITR); 165 166 for (int i = 0; i < NUMTHR; i++) { 167 (void) pthread_create(&tid[i], NULL, testlocale_thr, tname); 168 } 169 170 for (int i = 0; i < NUMTHR; i++) { 171 (void) pthread_join(tid[i], NULL); 172 } 173 test_passed(tname); 174 } 175 176 int 177 main(int argc, char **argv) 178 { 179 int optc; 180 181 while ((optc = getopt(argc, argv, "d")) != EOF) { 182 switch (optc) { 183 case 'd': 184 debug++; 185 break; 186 default: 187 (void) fprintf(stderr, "Usage: %s [-d]\n", argv[0]); 188 exit(1); 189 } 190 } 191 192 testlocale(); 193 194 exit(0); 195 }