summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/regress/lib/libc/locale/uselocale/Makefile9
-rw-r--r--src/regress/lib/libc/locale/uselocale/uselocale.c259
2 files changed, 268 insertions, 0 deletions
diff --git a/src/regress/lib/libc/locale/uselocale/Makefile b/src/regress/lib/libc/locale/uselocale/Makefile
new file mode 100644
index 0000000000..45c3b7e807
--- /dev/null
+++ b/src/regress/lib/libc/locale/uselocale/Makefile
@@ -0,0 +1,9 @@
1# $OpenBSD: Makefile,v 1.1 2017/08/10 14:45:42 schwarze Exp $
2
3PROG = uselocale
4LDFLAGS += -pthread
5
6run-regress-${PROG}: ${PROG}
7 ./${PROG}
8
9.include <bsd.regress.mk>
diff --git a/src/regress/lib/libc/locale/uselocale/uselocale.c b/src/regress/lib/libc/locale/uselocale/uselocale.c
new file mode 100644
index 0000000000..a40f77397a
--- /dev/null
+++ b/src/regress/lib/libc/locale/uselocale/uselocale.c
@@ -0,0 +1,259 @@
1/* $OpenBSD: uselocale.c,v 1.1 2017/08/10 14:45:42 schwarze Exp $ */
2/*
3 * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
4 * Copyright (c) 2015 Sebastien Marie <semarie@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <err.h>
20#include <errno.h>
21#include <locale.h>
22#include <pthread.h>
23#include <stdlib.h>
24#include <string.h>
25#include <time.h>
26
27#define _LOCALE_NONE (locale_t)0
28#define _LOCALE_C (locale_t)1
29#define _LOCALE_UTF8 (locale_t)2
30#define _LOCALE_BAD (locale_t)3
31
32#define SWITCH_SIGNAL 1
33#define SWITCH_WAIT 2
34
35/*
36 * test helpers for __LINE__
37 */
38#define test_newlocale(_e, _ee, _m, _l) \
39 _test_newlocale(_e, _ee, _m, _l, __LINE__)
40#define test_duplocale(_e, _ee, _l) _test_duplocale(_e, _ee, _l, __LINE__)
41#define test_uselocale(_e, _ee, _l) _test_uselocale(_e, _ee, _l, __LINE__)
42#define test_setlocale(_e, _c, _l) _test_setlocale(_e, _c, _l, __LINE__)
43#define test_MB_CUR_MAX(_e) _test_MB_CUR_MAX(_e, __LINE__)
44
45
46static void
47_test_newlocale(locale_t expected, int exp_err,
48 int mask, const char *locname, int line)
49{
50 locale_t result = newlocale(mask, locname, _LOCALE_NONE);
51
52 if (result != expected)
53 errx(1, "[%d] newlocale(%d, \"%s\")=\"%d\" [expected: \"%d\"]",
54 line, mask, locname, (int)result, (int)expected);
55 if (errno != exp_err)
56 errx(1, "[%d] newlocale(%d, \"%s\") errno=\"%d\" [expected:"
57 " \"%d\"]", line, mask, locname, errno, exp_err);
58 errno = 0;
59}
60
61static void
62_test_duplocale(locale_t expected, int exp_err, locale_t oldloc, int line)
63{
64 locale_t result = duplocale(oldloc);
65
66 if (result != expected)
67 errx(1, "[%d] duplocale(%d)=\"%d\" [expected: \"%d\"]",
68 line, (int)oldloc, (int)result, (int)expected);
69 if (errno != exp_err)
70 errx(1, "[%d] duplocale(%d) errno=\"%d\" [expected:"
71 " \"%d\"]", line, (int)oldloc, errno, exp_err);
72 errno = 0;
73}
74
75static void
76_test_uselocale(locale_t expected, int exp_err, locale_t newloc, int line)
77{
78 locale_t result = uselocale(newloc);
79
80 if (result != expected)
81 errx(1, "[%d] uselocale(%d)=\"%d\" [expected: \"%d\"]",
82 line, (int)newloc, (int)result, (int)expected);
83 if (errno != exp_err)
84 errx(1, "[%d] uselocale(%d) errno=\"%d\" [expected:"
85 " \"%d\"]", line, (int)newloc, errno, exp_err);
86 errno = 0;
87}
88
89static void
90_test_setlocale(const char *expected, int category, char *locale, int line)
91{
92 const char *result = setlocale(category, locale);
93
94 if (expected == NULL)
95 expected = "(null)";
96 if (result == NULL)
97 result = "(null)";
98 if (strcmp(expected, result) != 0)
99 errx(1, "[%d] setlocale(%d, \"%s\")=\"%s\" [expected: \"%s\"]",
100 line, category, locale, result, expected);
101 errno = 0;
102}
103
104static void
105_test_MB_CUR_MAX(size_t expected, int line)
106{
107 if (MB_CUR_MAX != expected)
108 errx(1, "[%d] MB_CUR_MAX=%ld [expected %ld]",
109 line, MB_CUR_MAX, expected);
110}
111
112static void
113switch_thread(int step, int flags)
114{
115 static pthread_mutexattr_t ma;
116 static struct timespec t;
117 static pthread_cond_t *c;
118 static pthread_mutex_t *m;
119 int irc;
120
121 if (m == NULL) {
122 if ((m = malloc(sizeof(*m))) == NULL)
123 err(1, NULL);
124 if ((irc = pthread_mutexattr_init(&ma)) != 0)
125 errc(1, irc, "pthread_mutexattr_init");
126 if ((irc = pthread_mutexattr_settype(&ma,
127 PTHREAD_MUTEX_STRICT_NP)) != 0)
128 errc(1, irc, "pthread_mutexattr_settype");
129 if ((irc = pthread_mutex_init(m, &ma)) != 0)
130 errc(1, irc, "pthread_mutex_init");
131 }
132 if (c == NULL) {
133 if ((c = malloc(sizeof(*c))) == NULL)
134 err(1, NULL);
135 if ((irc = pthread_cond_init(c, NULL)) != 0)
136 errc(1, irc, "pthread_cond_init");
137 }
138 if (flags & SWITCH_SIGNAL) {
139 if ((irc = pthread_cond_signal(c)) != 0)
140 errc(1, irc, "pthread_cond_signal(%d)", step);
141 }
142 if (flags & SWITCH_WAIT) {
143 if ((irc = pthread_mutex_trylock(m)) != 0)
144 errc(1, irc, "pthread_mutex_trylock(%d)", step);
145 t.tv_sec = time(NULL) + 2;
146 if ((irc = pthread_cond_timedwait(c, m, &t)) != 0)
147 errc(1, irc, "pthread_cond_timedwait(%d)", step);
148 if ((irc = pthread_mutex_unlock(m)) != 0)
149 errc(1, irc, "pthread_mutex_unlock(%d)", step);
150 }
151}
152
153static void *
154child_func(void *arg)
155{
156 /* Test invalid newlocale(3) arguments. */
157 test_newlocale(_LOCALE_NONE, EINVAL, LC_CTYPE_MASK, NULL);
158 test_MB_CUR_MAX(1);
159 test_newlocale(_LOCALE_NONE, EINVAL, LC_ALL_MASK + 1, "C.UTF-8");
160 test_MB_CUR_MAX(1);
161 test_newlocale(_LOCALE_NONE, ENOENT, LC_COLLATE_MASK, "C.INV");
162 test_MB_CUR_MAX(1);
163 setenv("LC_TIME", "C.INV", 1);
164 test_newlocale(_LOCALE_NONE, ENOENT, LC_TIME_MASK, "");
165 unsetenv("LC_TIME");
166 test_MB_CUR_MAX(1);
167 setenv("LC_CTYPE", "C.INV", 1);
168 test_newlocale(_LOCALE_NONE, ENOENT, LC_CTYPE_MASK, "");
169 test_MB_CUR_MAX(1);
170
171 /* Test duplocale(3). */
172 test_duplocale(_LOCALE_NONE, EINVAL, _LOCALE_UTF8);
173 test_duplocale(_LOCALE_C, 0, _LOCALE_C);
174 test_duplocale(_LOCALE_C, 0, LC_GLOBAL_LOCALE);
175
176 /* Test premature UTF-8 uselocale(3). */
177 test_uselocale(_LOCALE_NONE, EINVAL, _LOCALE_UTF8);
178 test_MB_CUR_MAX(1);
179 test_uselocale(LC_GLOBAL_LOCALE, 0, _LOCALE_NONE);
180
181 /* Test UTF-8 initialization. */
182 setenv("LC_CTYPE", "C.UTF-8", 1);
183 test_newlocale(_LOCALE_UTF8, 0, LC_CTYPE_MASK, "");
184 unsetenv("LC_CTYPE");
185 test_MB_CUR_MAX(1);
186 test_duplocale(_LOCALE_UTF8, 0, _LOCALE_UTF8);
187
188 /* Test invalid uselocale(3) argument. */
189 test_uselocale(_LOCALE_NONE, EINVAL, _LOCALE_BAD);
190 test_MB_CUR_MAX(1);
191 test_uselocale(LC_GLOBAL_LOCALE, 0, _LOCALE_NONE);
192
193 /* Test switching the thread locale. */
194 test_uselocale(LC_GLOBAL_LOCALE, 0, _LOCALE_UTF8);
195 test_MB_CUR_MAX(4);
196 test_uselocale(_LOCALE_UTF8, 0, _LOCALE_NONE);
197
198 /* Test non-ctype newlocale(3). */
199 test_newlocale(_LOCALE_C, 0, LC_MESSAGES_MASK, "en_US.UTF-8");
200
201 /* Temporarily switch to the main thread. */
202 switch_thread(2, SWITCH_SIGNAL | SWITCH_WAIT);
203
204 /* Test displaying the global locale while a local one is set. */
205 test_setlocale("C/C.UTF-8/C/C/C/C", LC_ALL, NULL);
206
207 /* Test switching the thread locale back. */
208 test_MB_CUR_MAX(4);
209 test_duplocale(_LOCALE_UTF8, 0, LC_GLOBAL_LOCALE);
210 test_uselocale(_LOCALE_UTF8, 0, _LOCALE_C);
211 test_MB_CUR_MAX(1);
212 test_uselocale(_LOCALE_C, 0, _LOCALE_NONE);
213
214 /* Test switching back to the global locale. */
215 test_uselocale(_LOCALE_C, 0, LC_GLOBAL_LOCALE);
216 test_MB_CUR_MAX(4);
217 test_uselocale(LC_GLOBAL_LOCALE, 0, _LOCALE_NONE);
218
219 /* Hand control back to the main thread. */
220 switch_thread(4, SWITCH_SIGNAL);
221 return NULL;
222}
223
224int
225main(void)
226{
227 pthread_t child_thread;
228 int irc;
229
230 /* Initialize environment. */
231 unsetenv("LC_ALL");
232 unsetenv("LC_COLLATE");
233 unsetenv("LC_CTYPE");
234 unsetenv("LC_MONETARY");
235 unsetenv("LC_NUMERIC");
236 unsetenv("LC_TIME");
237 unsetenv("LC_MESSAGES");
238 unsetenv("LANG");
239
240 /* First let the child do some tests. */
241 if ((irc = pthread_create(&child_thread, NULL, child_func, NULL)) != 0)
242 errc(1, irc, "pthread_create");
243 switch_thread(1, SWITCH_WAIT);
244
245 /* Check that the global locale is undisturbed. */
246 test_setlocale("C", LC_ALL, NULL);
247 test_MB_CUR_MAX(1);
248
249 /* Test setting the globale locale. */
250 test_setlocale("C.UTF-8", LC_CTYPE, "C.UTF-8");
251 test_MB_CUR_MAX(4);
252 test_uselocale(LC_GLOBAL_LOCALE, 0, _LOCALE_NONE);
253
254 /* Let the child do some more tests, then clean up. */
255 switch_thread(3, SWITCH_SIGNAL);
256 if ((irc = pthread_join(child_thread, NULL)) != 0)
257 errc(1, irc, "pthread_join");
258 return 0;
259}