1 /* $OpenBSD: setlocale.c,v 1.2 2015/08/23 07:33:50 guenther Exp $ */
2 /*
3  * Copyright (c) 2015 Sebastien Marie <semarie@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <err.h>
19 #include <locale.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 /*
25  * test helpers for __LINE__
26  */
27 #define test_setlocale(_e, _c, _l) _test_setlocale(_e, _c, _l, __LINE__)
28 #define test_MB_CUR_MAX(_e) _test_MB_CUR_MAX(_e, __LINE__)
29 #define test_isalpha(_e, _c) _test_isalpha(_e, _c, __LINE__)
30 
31 
32 static void
33 _test_setlocale(char *expected, int category, char *locale, int line)
34 {
35 	char *result = setlocale(category, locale);
36 
37 	if ((expected == NULL) || (result == NULL)) {
38 		if (expected == result)
39 			return;
40 
41 		errx(1, "[%d] setlocale(%d, \"%s\")=\"%s\" [expected: \"%s\"]",
42 		       line, category, locale, result, expected);
43 	}
44 
45 	if (strcmp(expected, result) != 0)
46 		errx(1, "[%d] setlocale(%d, \"%s\")=\"%s\" [expected: \"%s\"]",
47 		       line, category, locale, result, expected);
48 }
49 
50 static void
51 _test_MB_CUR_MAX(size_t expected, int line)
52 {
53 	if (MB_CUR_MAX != expected)
54 		errx(1, "[%d] MB_CUR_MAX=%ld [expected %ld]",
55 			line, MB_CUR_MAX, expected);
56 }
57 
58 static void
59 _test_isalpha(int expected, int c, int line)
60 {
61 	int result = isalpha(c);
62 	if (!!result != expected)
63 		errx(1, "[%d] isalpha(%d)=%d [expected %d]",
64 			line, c, result, expected);
65 }
66 
67 int
68 main(int argc, char *argv[])
69 {
70 	/* check initial state (should be "C") */
71 	test_setlocale("C", LC_ALL, NULL); /* check */
72 	test_MB_CUR_MAX(1);
73 	test_isalpha(0, 0xe9); /* iso-8859-1 eacute */
74 
75 	/* load from env */
76 	/* NOTE: we don't support non-C locales for some categories */
77 	/*test_setlocale("fr_FR.UTF-8", LC_ALL, "");*/ /* set */
78 	test_setlocale("fr_FR.UTF-8", LC_CTYPE, ""); /* set */
79 	test_setlocale("fr_FR.UTF-8", LC_MESSAGES, ""); /* set */
80 	test_MB_CUR_MAX(4);
81 	test_isalpha(0, 0xe9); /* iso-8859-1 eacute */
82 
83 	test_setlocale("C", LC_MESSAGES, "C"); /* set */
84 	test_MB_CUR_MAX(4);
85 	test_setlocale("C/fr_FR.UTF-8/C/C/C/C", LC_ALL, NULL); /* check */
86 
87 	test_setlocale("C", LC_CTYPE, "C"); /* set */
88 	test_MB_CUR_MAX(1);
89 	test_setlocale("C", LC_ALL, NULL); /* check */
90 
91 	/* check for errors on checking */
92 	test_setlocale("C", LC_ALL, "C"); /* reset */
93 	test_setlocale(NULL, -1, NULL);
94 	test_setlocale(NULL, _LC_LAST, NULL);
95 	test_setlocale(NULL, _LC_LAST+0xff, NULL);
96 	test_setlocale("C", LC_ALL, NULL); /* check */
97 
98 	/* check for errors on setting */
99 	test_setlocale(NULL, -1, "");
100 	test_setlocale(NULL, _LC_LAST, "");
101 	test_setlocale(NULL, _LC_LAST+0xff, "");
102 	test_setlocale("C", LC_ALL, NULL); /* check */
103 
104 	/* no codeset, fallback to ASCII */
105 	test_setlocale("C", LC_ALL, "C"); /* reset */
106 	test_setlocale("invalid", LC_CTYPE, "invalid"); /* set */
107 	test_setlocale("invalid", LC_CTYPE, NULL);
108 	test_MB_CUR_MAX(1);
109 	test_isalpha(0, 0xe9); /* iso-8859-1 eacute */
110 
111 	/* with codeset */
112 	test_setlocale("C", LC_ALL, "C"); /* reset */
113 	test_setlocale("invalid.UTF-8", LC_CTYPE, "invalid.UTF-8"); /* set */
114 	test_setlocale("invalid.UTF-8", LC_CTYPE, NULL);
115 	test_MB_CUR_MAX(4);
116 
117 	/* with invalid codeset (is an error) */
118 	test_setlocale("C", LC_ALL, "C"); /* reset */
119 	test_setlocale(NULL, LC_CTYPE, "fr_FR.invalid"); /* set */
120 	test_setlocale("C", LC_CTYPE, NULL);
121 	test_MB_CUR_MAX(1);
122 
123 	return (EXIT_SUCCESS);
124 }
125