1*4f2483e5SBill Sommerfeld /*
2*4f2483e5SBill Sommerfeld * This file and its contents are supplied under the terms of the
3*4f2483e5SBill Sommerfeld * Common Development and Distribution License ("CDDL"), version 1.0.
4*4f2483e5SBill Sommerfeld * You may only use this file in accordance with the terms of version
5*4f2483e5SBill Sommerfeld * 1.0 of the CDDL.
6*4f2483e5SBill Sommerfeld *
7*4f2483e5SBill Sommerfeld * A full copy of the text of the CDDL should have accompanied this
8*4f2483e5SBill Sommerfeld * source. A copy of the CDDL is also available via the Internet at
9*4f2483e5SBill Sommerfeld * http://www.illumos.org/license/CDDL.
10*4f2483e5SBill Sommerfeld */
11*4f2483e5SBill Sommerfeld
12*4f2483e5SBill Sommerfeld /*
13*4f2483e5SBill Sommerfeld * Copyright 2025 Oxide Computer Company
14*4f2483e5SBill Sommerfeld * Copyright 2025 Bill Sommerfeld
15*4f2483e5SBill Sommerfeld */
16*4f2483e5SBill Sommerfeld
17*4f2483e5SBill Sommerfeld /*
18*4f2483e5SBill Sommerfeld * Locale test for the XPG4 version of wcsftime(), which takes a char *
19*4f2483e5SBill Sommerfeld * format; later standards use a wchar_t * format.
20*4f2483e5SBill Sommerfeld */
21*4f2483e5SBill Sommerfeld
22*4f2483e5SBill Sommerfeld #define _XOPEN_SOURCE
23*4f2483e5SBill Sommerfeld #define _XOPEN_VERSION 4
24*4f2483e5SBill Sommerfeld
25*4f2483e5SBill Sommerfeld #include <err.h>
26*4f2483e5SBill Sommerfeld #include <stdlib.h>
27*4f2483e5SBill Sommerfeld #include <wchar.h>
28*4f2483e5SBill Sommerfeld #include <locale.h>
29*4f2483e5SBill Sommerfeld #include <sys/sysmacros.h>
30*4f2483e5SBill Sommerfeld #include <sys/debug.h>
31*4f2483e5SBill Sommerfeld #include <stdbool.h>
32*4f2483e5SBill Sommerfeld #include <string.h>
33*4f2483e5SBill Sommerfeld
34*4f2483e5SBill Sommerfeld #ifndef _XPG4
35*4f2483e5SBill Sommerfeld #error _XPG4 should be defined for this file
36*4f2483e5SBill Sommerfeld #endif
37*4f2483e5SBill Sommerfeld
38*4f2483e5SBill Sommerfeld #ifdef _XPG5
39*4f2483e5SBill Sommerfeld #error _XPG5 should not be defined for this file
40*4f2483e5SBill Sommerfeld #endif
41*4f2483e5SBill Sommerfeld
42*4f2483e5SBill Sommerfeld /*
43*4f2483e5SBill Sommerfeld * We're just testing that the desired locale reaches the underlying
44*4f2483e5SBill Sommerfeld * formatter so we only look at one attribute: the full month name.
45*4f2483e5SBill Sommerfeld */
46*4f2483e5SBill Sommerfeld static const struct test_locale {
47*4f2483e5SBill Sommerfeld const char *name;
48*4f2483e5SBill Sommerfeld const char *monthname;
49*4f2483e5SBill Sommerfeld } locales[] = {
50*4f2483e5SBill Sommerfeld { "C.UTF-8", "December" },
51*4f2483e5SBill Sommerfeld {"ja_JP.UTF-8", "12月", },
52*4f2483e5SBill Sommerfeld {"de_DE.UTF-8", "Dezember"},
53*4f2483e5SBill Sommerfeld {"en_US.UTF-8", "December" },
54*4f2483e5SBill Sommerfeld };
55*4f2483e5SBill Sommerfeld
56*4f2483e5SBill Sommerfeld struct tm sample_tm = { .tm_mon = 11, .tm_wday = 1 };
57*4f2483e5SBill Sommerfeld
58*4f2483e5SBill Sommerfeld #define WCSSIZE 100
59*4f2483e5SBill Sommerfeld #define CSIZE 200
60*4f2483e5SBill Sommerfeld
61*4f2483e5SBill Sommerfeld /*
62*4f2483e5SBill Sommerfeld * Test that the correct decimal point is recognized.
63*4f2483e5SBill Sommerfeld * Use old version of wcsftime which takes a char * parameter.
64*4f2483e5SBill Sommerfeld */
65*4f2483e5SBill Sommerfeld static bool
test_locale(const char * name,const char * monthname)66*4f2483e5SBill Sommerfeld test_locale(const char *name, const char *monthname)
67*4f2483e5SBill Sommerfeld {
68*4f2483e5SBill Sommerfeld bool result_ok = true;
69*4f2483e5SBill Sommerfeld wchar_t wcs[WCSSIZE];
70*4f2483e5SBill Sommerfeld char cstring[CSIZE];
71*4f2483e5SBill Sommerfeld
72*4f2483e5SBill Sommerfeld size_t len;
73*4f2483e5SBill Sommerfeld
74*4f2483e5SBill Sommerfeld if (setlocale(LC_ALL, name) == NULL) {
75*4f2483e5SBill Sommerfeld err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
76*4f2483e5SBill Sommerfeld "set locale %s", name);
77*4f2483e5SBill Sommerfeld }
78*4f2483e5SBill Sommerfeld
79*4f2483e5SBill Sommerfeld len = wcsftime(wcs, WCSSIZE, "%B", &sample_tm);
80*4f2483e5SBill Sommerfeld if (len == (size_t)-1) {
81*4f2483e5SBill Sommerfeld warn("TEST FAILED: wcsftime_l returned -1");
82*4f2483e5SBill Sommerfeld result_ok = false;
83*4f2483e5SBill Sommerfeld }
84*4f2483e5SBill Sommerfeld
85*4f2483e5SBill Sommerfeld if (wcstombs(cstring, wcs, CSIZE) == (size_t)-1) {
86*4f2483e5SBill Sommerfeld err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
87*4f2483e5SBill Sommerfeld "convert wide char string back to multibyte string");
88*4f2483e5SBill Sommerfeld }
89*4f2483e5SBill Sommerfeld
90*4f2483e5SBill Sommerfeld if (strcmp(cstring, monthname)) {
91*4f2483e5SBill Sommerfeld warn("TEST FAILED: Wrong month name for locale %s month %d: "
92*4f2483e5SBill Sommerfeld "got %s expected %s", name, sample_tm.tm_mon+1,
93*4f2483e5SBill Sommerfeld cstring, monthname);
94*4f2483e5SBill Sommerfeld result_ok = false;
95*4f2483e5SBill Sommerfeld }
96*4f2483e5SBill Sommerfeld return (result_ok);
97*4f2483e5SBill Sommerfeld }
98*4f2483e5SBill Sommerfeld
99*4f2483e5SBill Sommerfeld
100*4f2483e5SBill Sommerfeld int
main(void)101*4f2483e5SBill Sommerfeld main(void)
102*4f2483e5SBill Sommerfeld {
103*4f2483e5SBill Sommerfeld int ret = EXIT_SUCCESS;
104*4f2483e5SBill Sommerfeld size_t i;
105*4f2483e5SBill Sommerfeld
106*4f2483e5SBill Sommerfeld for (i = 0; i < ARRAY_SIZE(locales); i++) {
107*4f2483e5SBill Sommerfeld if (!test_locale(locales[i].name, locales[i].monthname))
108*4f2483e5SBill Sommerfeld ret = EXIT_FAILURE;
109*4f2483e5SBill Sommerfeld }
110*4f2483e5SBill Sommerfeld
111*4f2483e5SBill Sommerfeld if (ret == EXIT_SUCCESS) {
112*4f2483e5SBill Sommerfeld (void) printf("All tests completed successfully\n");
113*4f2483e5SBill Sommerfeld }
114*4f2483e5SBill Sommerfeld
115*4f2483e5SBill Sommerfeld return (ret);
116*4f2483e5SBill Sommerfeld }
117