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