1*538aa54dSGarrett D'Amore /* 2*538aa54dSGarrett D'Amore * This file and its contents are supplied under the terms of the 3*538aa54dSGarrett D'Amore * Common Development and Distribution License ("CDDL"), version 1.0. 4*538aa54dSGarrett D'Amore * You may only use this file in accordance with the terms of version 5*538aa54dSGarrett D'Amore * 1.0 of the CDDL. 6*538aa54dSGarrett D'Amore * 7*538aa54dSGarrett D'Amore * A full copy of the text of the CDDL should have accompanied this 8*538aa54dSGarrett D'Amore * source. A copy of the CDDL is also available via the Internet at 9*538aa54dSGarrett D'Amore * http://www.illumos.org/license/CDDL. 10*538aa54dSGarrett D'Amore */ 11*538aa54dSGarrett D'Amore 12*538aa54dSGarrett D'Amore /* 13*538aa54dSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org> 14*538aa54dSGarrett D'Amore */ 15*538aa54dSGarrett D'Amore 16*538aa54dSGarrett D'Amore /* 17*538aa54dSGarrett D'Amore * This program tests that newlocale and uselocale work properly in 18*538aa54dSGarrett D'Amore * multi-threaded programs. In order for it to work, it requires that 19*538aa54dSGarrett D'Amore * some additional locales be installed. 20*538aa54dSGarrett D'Amore */ 21*538aa54dSGarrett D'Amore 22*538aa54dSGarrett D'Amore #include <stdio.h> 23*538aa54dSGarrett D'Amore #include <stdlib.h> 24*538aa54dSGarrett D'Amore #include <string.h> 25*538aa54dSGarrett D'Amore #include <locale.h> 26*538aa54dSGarrett D'Amore #include <libintl.h> 27*538aa54dSGarrett D'Amore #include <langinfo.h> 28*538aa54dSGarrett D'Amore #include <nl_types.h> 29*538aa54dSGarrett D'Amore #include <err.h> 30*538aa54dSGarrett D'Amore #include <errno.h> 31*538aa54dSGarrett D'Amore #include <unistd.h> 32*538aa54dSGarrett D'Amore #include "test_common.h" 33*538aa54dSGarrett D'Amore 34*538aa54dSGarrett D'Amore /* 35*538aa54dSGarrett D'Amore * Note that on some platforms, different symbols are used. For example, 36*538aa54dSGarrett D'Amore * MacOS Mavericks uses "Eu" for Euro symbol, instead of €. If the locale 37*538aa54dSGarrett D'Amore * data changes, then this program will need to update to reflect that. 38*538aa54dSGarrett D'Amore * 39*538aa54dSGarrett D'Amore * Note also that this file is easiest edited with a UTF-8 capable editor, 40*538aa54dSGarrett D'Amore * as there are embedded UTF-8 symbols in some of the strings. 41*538aa54dSGarrett D'Amore */ 42*538aa54dSGarrett D'Amore struct langinfo_test { 43*538aa54dSGarrett D'Amore nl_item param; 44*538aa54dSGarrett D'Amore const char *value; 45*538aa54dSGarrett D'Amore }; 46*538aa54dSGarrett D'Amore 47*538aa54dSGarrett D'Amore struct langinfo_test C_data[] = { 48*538aa54dSGarrett D'Amore { CODESET, "646" }, 49*538aa54dSGarrett D'Amore { D_T_FMT, "%a %b %e %H:%M:%S %Y" }, 50*538aa54dSGarrett D'Amore { D_FMT, "%m/%d/%y" }, 51*538aa54dSGarrett D'Amore { T_FMT, "%H:%M:%S" }, 52*538aa54dSGarrett D'Amore { T_FMT_AMPM, "%I:%M:%S %p" }, 53*538aa54dSGarrett D'Amore { AM_STR, "AM" }, 54*538aa54dSGarrett D'Amore { PM_STR, "PM" }, 55*538aa54dSGarrett D'Amore { ERA, "" }, 56*538aa54dSGarrett D'Amore { ERA_D_FMT, "" }, 57*538aa54dSGarrett D'Amore { ERA_D_T_FMT, "" }, 58*538aa54dSGarrett D'Amore { ERA_T_FMT, "" }, 59*538aa54dSGarrett D'Amore { DAY_1, "Sunday" }, 60*538aa54dSGarrett D'Amore { DAY_7, "Saturday" }, 61*538aa54dSGarrett D'Amore { ABDAY_1, "Sun" }, 62*538aa54dSGarrett D'Amore { ABDAY_7, "Sat" }, 63*538aa54dSGarrett D'Amore { MON_1, "January" }, 64*538aa54dSGarrett D'Amore { MON_12, "December" }, 65*538aa54dSGarrett D'Amore { ABMON_1, "Jan" }, 66*538aa54dSGarrett D'Amore { ABMON_12, "Dec" }, 67*538aa54dSGarrett D'Amore { RADIXCHAR, "." }, 68*538aa54dSGarrett D'Amore { THOUSEP, "" }, 69*538aa54dSGarrett D'Amore { YESSTR, "yes" }, 70*538aa54dSGarrett D'Amore { NOSTR, "no" }, 71*538aa54dSGarrett D'Amore { YESEXPR, "^[yY]" }, 72*538aa54dSGarrett D'Amore { NOEXPR, "^[nN]" }, 73*538aa54dSGarrett D'Amore { CRNCYSTR, "" }, 74*538aa54dSGarrett D'Amore { -1, NULL } 75*538aa54dSGarrett D'Amore }; 76*538aa54dSGarrett D'Amore 77*538aa54dSGarrett D'Amore struct langinfo_test en_us_utf8_data[] = { 78*538aa54dSGarrett D'Amore { CODESET, "UTF-8" }, 79*538aa54dSGarrett D'Amore { D_T_FMT, "%B %e, %Y %I:%M:%S %p %Z" }, 80*538aa54dSGarrett D'Amore { D_FMT, "%m/%e/%y" }, 81*538aa54dSGarrett D'Amore { T_FMT, "%I:%M:%S %p" }, 82*538aa54dSGarrett D'Amore { T_FMT_AMPM, "%I:%M:%S %p" }, 83*538aa54dSGarrett D'Amore { AM_STR, "AM" }, 84*538aa54dSGarrett D'Amore { PM_STR, "PM" }, 85*538aa54dSGarrett D'Amore { ERA, "" }, 86*538aa54dSGarrett D'Amore { ERA_D_FMT, "" }, 87*538aa54dSGarrett D'Amore { ERA_D_T_FMT, "" }, 88*538aa54dSGarrett D'Amore { ERA_T_FMT, "" }, 89*538aa54dSGarrett D'Amore { DAY_1, "Sunday" }, 90*538aa54dSGarrett D'Amore { DAY_7, "Saturday" }, 91*538aa54dSGarrett D'Amore { ABDAY_1, "Sun" }, 92*538aa54dSGarrett D'Amore { ABDAY_7, "Sat" }, 93*538aa54dSGarrett D'Amore { MON_1, "January" }, 94*538aa54dSGarrett D'Amore { MON_12, "December" }, 95*538aa54dSGarrett D'Amore { ABMON_1, "Jan" }, 96*538aa54dSGarrett D'Amore { ABMON_12, "Dec" }, 97*538aa54dSGarrett D'Amore { RADIXCHAR, "." }, 98*538aa54dSGarrett D'Amore { THOUSEP, "," }, 99*538aa54dSGarrett D'Amore { YESSTR, "yes" }, 100*538aa54dSGarrett D'Amore { NOSTR, "no" }, 101*538aa54dSGarrett D'Amore { YESEXPR, "^(([yY]([eE][sS])?))" }, 102*538aa54dSGarrett D'Amore { NOEXPR, "^(([nN]([oO])?))" }, 103*538aa54dSGarrett D'Amore { CRNCYSTR, "-$" }, 104*538aa54dSGarrett D'Amore { -1, NULL } 105*538aa54dSGarrett D'Amore }; 106*538aa54dSGarrett D'Amore 107*538aa54dSGarrett D'Amore struct langinfo_test en_gb_latin15_data[] = { 108*538aa54dSGarrett D'Amore { CODESET, "ISO8859-15" }, 109*538aa54dSGarrett D'Amore { D_T_FMT, "%e %B %Y %H:%M:%S %Z" }, 110*538aa54dSGarrett D'Amore { D_FMT, "%d/%m/%Y" }, 111*538aa54dSGarrett D'Amore { T_FMT, "%H:%M:%S" }, 112*538aa54dSGarrett D'Amore { T_FMT_AMPM, "%I:%M:%S %p" }, 113*538aa54dSGarrett D'Amore { AM_STR, "AM" }, 114*538aa54dSGarrett D'Amore { PM_STR, "PM" }, 115*538aa54dSGarrett D'Amore { ERA, "" }, 116*538aa54dSGarrett D'Amore { ERA_D_FMT, "" }, 117*538aa54dSGarrett D'Amore { ERA_D_T_FMT, "" }, 118*538aa54dSGarrett D'Amore { ERA_T_FMT, "" }, 119*538aa54dSGarrett D'Amore { DAY_1, "Sunday" }, 120*538aa54dSGarrett D'Amore { DAY_7, "Saturday" }, 121*538aa54dSGarrett D'Amore { ABDAY_1, "Sun" }, 122*538aa54dSGarrett D'Amore { ABDAY_7, "Sat" }, 123*538aa54dSGarrett D'Amore { MON_1, "January" }, 124*538aa54dSGarrett D'Amore { MON_12, "December" }, 125*538aa54dSGarrett D'Amore { ABMON_1, "Jan" }, 126*538aa54dSGarrett D'Amore { ABMON_12, "Dec" }, 127*538aa54dSGarrett D'Amore { RADIXCHAR, "." }, 128*538aa54dSGarrett D'Amore { THOUSEP, "," }, 129*538aa54dSGarrett D'Amore { YESSTR, "yes" }, 130*538aa54dSGarrett D'Amore { NOSTR, "no" }, 131*538aa54dSGarrett D'Amore { YESEXPR, "^(([yY]([eE][sS])?))" }, 132*538aa54dSGarrett D'Amore { NOEXPR, "^(([nN]([oO])?))" }, 133*538aa54dSGarrett D'Amore { CRNCYSTR, "-\243" }, 134*538aa54dSGarrett D'Amore { -1, NULL } 135*538aa54dSGarrett D'Amore }; 136*538aa54dSGarrett D'Amore 137*538aa54dSGarrett D'Amore struct langinfo_test ru_ru_utf8_data[] = { 138*538aa54dSGarrett D'Amore { CODESET, "UTF-8" }, 139*538aa54dSGarrett D'Amore { D_T_FMT, "%e %B %Y г. %H:%M:%S %Z"}, 140*538aa54dSGarrett D'Amore { D_FMT, "%d.%m.%y" }, 141*538aa54dSGarrett D'Amore { T_FMT, "%H:%M:%S" }, 142*538aa54dSGarrett D'Amore { T_FMT_AMPM, "%I:%M:%S %p" }, 143*538aa54dSGarrett D'Amore { AM_STR, "до полудня" }, 144*538aa54dSGarrett D'Amore { PM_STR, "после полудня" }, 145*538aa54dSGarrett D'Amore { ERA, "" }, 146*538aa54dSGarrett D'Amore { ERA_D_FMT, "" }, 147*538aa54dSGarrett D'Amore { ERA_D_T_FMT, "" }, 148*538aa54dSGarrett D'Amore { ERA_T_FMT, "" }, 149*538aa54dSGarrett D'Amore { DAY_1, "воскресенье" }, 150*538aa54dSGarrett D'Amore { DAY_7, "суббота" }, 151*538aa54dSGarrett D'Amore { ABDAY_1, "вс" }, 152*538aa54dSGarrett D'Amore { ABDAY_7, "сб" }, 153*538aa54dSGarrett D'Amore { MON_1, "января" }, 154*538aa54dSGarrett D'Amore { MON_12, "декабря" }, 155*538aa54dSGarrett D'Amore { ABMON_1, "янв" }, 156*538aa54dSGarrett D'Amore { ABMON_12, "дек" }, 157*538aa54dSGarrett D'Amore { RADIXCHAR, "," }, 158*538aa54dSGarrett D'Amore { THOUSEP, " " }, 159*538aa54dSGarrett D'Amore { YESSTR, "да" }, 160*538aa54dSGarrett D'Amore { NOSTR, "нет" }, 161*538aa54dSGarrett D'Amore { YESEXPR, "^(([дД]([аА])?)|([yY]([eE][sS])?))" }, 162*538aa54dSGarrett D'Amore { NOEXPR, "^(([нН]([еЕ][тТ])?)|([nN]([oO])?))" }, 163*538aa54dSGarrett D'Amore { CRNCYSTR, "+руб." }, 164*538aa54dSGarrett D'Amore { -1, NULL } 165*538aa54dSGarrett D'Amore }; 166*538aa54dSGarrett D'Amore 167*538aa54dSGarrett D'Amore struct { 168*538aa54dSGarrett D'Amore const char *locale; 169*538aa54dSGarrett D'Amore struct langinfo_test *loctest; 170*538aa54dSGarrett D'Amore } locales[] = { 171*538aa54dSGarrett D'Amore { "C", C_data }, 172*538aa54dSGarrett D'Amore { "en_US.UTF-8", en_us_utf8_data }, 173*538aa54dSGarrett D'Amore { "en_GB.ISO8859-15", en_gb_latin15_data }, 174*538aa54dSGarrett D'Amore { "ru_RU.UTF-8", ru_ru_utf8_data }, 175*538aa54dSGarrett D'Amore { NULL, NULL } 176*538aa54dSGarrett D'Amore }; 177*538aa54dSGarrett D'Amore 178*538aa54dSGarrett D'Amore void 179*538aa54dSGarrett D'Amore test_nl_langinfo_1(const char *locale, struct langinfo_test *test) 180*538aa54dSGarrett D'Amore { 181*538aa54dSGarrett D'Amore char tname[128]; 182*538aa54dSGarrett D'Amore char *v; 183*538aa54dSGarrett D'Amore test_t t; 184*538aa54dSGarrett D'Amore 185*538aa54dSGarrett D'Amore (void) snprintf(tname, sizeof (tname), "nl_langinfo (locale %s)", 186*538aa54dSGarrett D'Amore locale); 187*538aa54dSGarrett D'Amore t = test_start(tname); 188*538aa54dSGarrett D'Amore 189*538aa54dSGarrett D'Amore v = setlocale(LC_ALL, locale); 190*538aa54dSGarrett D'Amore if (v == NULL) { 191*538aa54dSGarrett D'Amore test_failed(t, "setlocale failed: %s", strerror(errno)); 192*538aa54dSGarrett D'Amore } 193*538aa54dSGarrett D'Amore if (strcmp(v, locale) != 0) { 194*538aa54dSGarrett D'Amore test_failed(t, "setlocale got %s instead of %s", v, locale); 195*538aa54dSGarrett D'Amore } 196*538aa54dSGarrett D'Amore 197*538aa54dSGarrett D'Amore for (int i = 0; test[i].value != NULL; i++) { 198*538aa54dSGarrett D'Amore v = nl_langinfo(test[i].param); 199*538aa54dSGarrett D'Amore test_debugf(t, "%d: expect [%s], got [%s]", 200*538aa54dSGarrett D'Amore test[i].param, test[i].value, v); 201*538aa54dSGarrett D'Amore if (strcmp(v, test[i].value) != 0) { 202*538aa54dSGarrett D'Amore test_failed(t, 203*538aa54dSGarrett D'Amore "param %d wrong, expected [%s], got [%s]", 204*538aa54dSGarrett D'Amore test[i].param, test[i].value, v); 205*538aa54dSGarrett D'Amore } 206*538aa54dSGarrett D'Amore } 207*538aa54dSGarrett D'Amore test_passed(t); 208*538aa54dSGarrett D'Amore } 209*538aa54dSGarrett D'Amore 210*538aa54dSGarrett D'Amore void 211*538aa54dSGarrett D'Amore test_nl_langinfo_l(const char *locale, struct langinfo_test *test) 212*538aa54dSGarrett D'Amore { 213*538aa54dSGarrett D'Amore char tname[128]; 214*538aa54dSGarrett D'Amore char *v; 215*538aa54dSGarrett D'Amore test_t t; 216*538aa54dSGarrett D'Amore locale_t loc; 217*538aa54dSGarrett D'Amore 218*538aa54dSGarrett D'Amore (void) snprintf(tname, sizeof (tname), "nl_langinfo_l (locale %s)", 219*538aa54dSGarrett D'Amore locale); 220*538aa54dSGarrett D'Amore t = test_start(tname); 221*538aa54dSGarrett D'Amore 222*538aa54dSGarrett D'Amore v = setlocale(LC_ALL, "C"); 223*538aa54dSGarrett D'Amore if (v == NULL) { 224*538aa54dSGarrett D'Amore test_failed(t, "setlocale failed: %s", strerror(errno)); 225*538aa54dSGarrett D'Amore } 226*538aa54dSGarrett D'Amore if (strcmp(v, "C") != 0) { 227*538aa54dSGarrett D'Amore test_failed(t, "setlocale got %s instead of %s", v, "C"); 228*538aa54dSGarrett D'Amore } 229*538aa54dSGarrett D'Amore 230*538aa54dSGarrett D'Amore loc = newlocale(LC_ALL_MASK, locale, NULL); 231*538aa54dSGarrett D'Amore if (loc == NULL) { 232*538aa54dSGarrett D'Amore test_failed(t, "newlocale failed: %s", strerror(errno)); 233*538aa54dSGarrett D'Amore } 234*538aa54dSGarrett D'Amore 235*538aa54dSGarrett D'Amore for (int i = 0; test[i].value != NULL; i++) { 236*538aa54dSGarrett D'Amore v = nl_langinfo_l(test[i].param, loc); 237*538aa54dSGarrett D'Amore test_debugf(t, "%d: expect [%s], got [%s]", 238*538aa54dSGarrett D'Amore test[i].param, test[i].value, v); 239*538aa54dSGarrett D'Amore if (strcmp(v, test[i].value) != 0) { 240*538aa54dSGarrett D'Amore test_failed(t, 241*538aa54dSGarrett D'Amore "param %d wrong, expected [%s], got [%s]", 242*538aa54dSGarrett D'Amore test[i].param, test[i].value, v); 243*538aa54dSGarrett D'Amore } 244*538aa54dSGarrett D'Amore } 245*538aa54dSGarrett D'Amore test_passed(t); 246*538aa54dSGarrett D'Amore } 247*538aa54dSGarrett D'Amore void 248*538aa54dSGarrett D'Amore test_nl_langinfo(void) 249*538aa54dSGarrett D'Amore { 250*538aa54dSGarrett D'Amore for (int i = 0; locales[i].locale != NULL; i++) { 251*538aa54dSGarrett D'Amore test_nl_langinfo_1(locales[i].locale, locales[i].loctest); 252*538aa54dSGarrett D'Amore test_nl_langinfo_l(locales[i].locale, locales[i].loctest); 253*538aa54dSGarrett D'Amore } 254*538aa54dSGarrett D'Amore } 255*538aa54dSGarrett D'Amore 256*538aa54dSGarrett D'Amore int 257*538aa54dSGarrett D'Amore main(int argc, char **argv) 258*538aa54dSGarrett D'Amore { 259*538aa54dSGarrett D'Amore int optc; 260*538aa54dSGarrett D'Amore 261*538aa54dSGarrett D'Amore while ((optc = getopt(argc, argv, "df")) != EOF) { 262*538aa54dSGarrett D'Amore switch (optc) { 263*538aa54dSGarrett D'Amore case 'd': 264*538aa54dSGarrett D'Amore test_set_debug(); 265*538aa54dSGarrett D'Amore break; 266*538aa54dSGarrett D'Amore case 'f': 267*538aa54dSGarrett D'Amore test_set_force(); 268*538aa54dSGarrett D'Amore break; 269*538aa54dSGarrett D'Amore default: 270*538aa54dSGarrett D'Amore (void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]); 271*538aa54dSGarrett D'Amore exit(1); 272*538aa54dSGarrett D'Amore } 273*538aa54dSGarrett D'Amore } 274*538aa54dSGarrett D'Amore 275*538aa54dSGarrett D'Amore test_nl_langinfo(); 276*538aa54dSGarrett D'Amore 277*538aa54dSGarrett D'Amore exit(0); 278*538aa54dSGarrett D'Amore } 279