1 /* $OpenBSD: setlocale.c,v 1.4 2018/03/29 16:34:25 schwarze 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 #include <ctype.h>
24 
25 /*
26  * test helpers for __LINE__
27  */
28 #define test_setlocale(_e, _c, _l) _test_setlocale(_e, _c, _l, __LINE__)
29 #define test_MB_CUR_MAX(_e) _test_MB_CUR_MAX(_e, __LINE__)
30 #define test_isalpha(_e, _c) _test_isalpha(_e, _c, __LINE__)
31 
32 
33 static void
34 _test_setlocale(char *expected, int category, char *locale, int line)
35 {
36 	char *result = setlocale(category, locale);
37 
38 	if ((expected == NULL) || (result == NULL)) {
39 		if (expected == result)
40 			return;
41 
42 		errx(1, "[%d] setlocale(%d, \"%s\")=\"%s\" [expected: \"%s\"]",
43 		       line, category, locale, result, expected);
44 	}
45 
46 	if (strcmp(expected, result) != 0)
47 		errx(1, "[%d] setlocale(%d, \"%s\")=\"%s\" [expected: \"%s\"]",
48 		       line, category, locale, result, expected);
49 }
50 
51 static void
52 _test_MB_CUR_MAX(size_t expected, int line)
53 {
54 	if (MB_CUR_MAX != expected)
55 		errx(1, "[%d] MB_CUR_MAX=%ld [expected %ld]",
56 			line, MB_CUR_MAX, expected);
57 }
58 
59 static void
60 _test_isalpha(int expected, int c, int line)
61 {
62 	int result = isalpha(c);
63 	if (!!result != expected)
64 		errx(1, "[%d] isalpha(%d)=%d [expected %d]",
65 			line, c, result, expected);
66 }
67 
68 int
69 main(int argc, char *argv[])
70 {
71 	/* check initial state (should be "C") */
72 	test_setlocale("C", LC_ALL, NULL); /* check */
73 	test_MB_CUR_MAX(1);
74 	test_isalpha(0, 0xe9); /* iso-8859-1 eacute */
75 
76 	/* load from env */
77 	/* NOTE: we don't support non-C locales for some categories */
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_setlocale("C/invalid.UTF-8/C/C/C/C", LC_ALL, NULL);
116 	test_MB_CUR_MAX(4);
117 
118 	/* with invalid codeset (is an error) */
119 	test_setlocale("C", LC_ALL, "C"); /* reset */
120 	test_setlocale(NULL, LC_CTYPE, "fr_FR.invalid"); /* set */
121 	test_setlocale("C", LC_CTYPE, NULL);
122 	test_MB_CUR_MAX(1);
123 
124 	return (EXIT_SUCCESS);
125 }
126