1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright 2023 Yuri Pankov <yuripv@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 30 #include <locale.h> 31 32 #include <atf-c.h> 33 34 struct { 35 int lpmask; 36 const char *lpname; 37 } lparts[] = { 38 { LC_COLLATE_MASK, "LC_COLLATE" }, 39 { LC_CTYPE_MASK, "LC_CTYPE" }, 40 { LC_MONETARY_MASK, "LC_MONETARY" }, 41 { LC_NUMERIC_MASK, "LC_NUMERIC" }, 42 { LC_TIME_MASK, "LC_TIME" }, 43 { LC_MESSAGES_MASK, "LC_MESSAGES" }, 44 }; 45 46 static void 47 check_lparts(const char *expected) 48 { 49 int i; 50 51 for (i = 0; i < nitems(lparts); i++) { 52 const char *actual; 53 54 actual = querylocale(lparts[i].lpmask, uselocale(NULL)); 55 ATF_CHECK_STREQ_MSG(expected, actual, "wrong value for %s", 56 lparts[i].lpname); 57 } 58 } 59 60 static void 61 do_locale_switch(const char *loc1, const char *loc2) 62 { 63 locale_t l1, l2; 64 65 /* Create and use the first locale */ 66 l1 = newlocale(LC_ALL_MASK, loc1, NULL); 67 ATF_REQUIRE(l1 != NULL); 68 ATF_REQUIRE(uselocale(l1) != NULL); 69 check_lparts(loc1); 70 /* 71 * Create and use second locale, creation deliberately done only after 72 * the first locale check as newlocale() call would previously clobber 73 * the first locale contents. 74 */ 75 l2 = newlocale(LC_ALL_MASK, loc2, NULL); 76 ATF_REQUIRE(l2 != NULL); 77 ATF_REQUIRE(uselocale(l2) != NULL); 78 check_lparts(loc2); 79 /* Switch back to first locale */ 80 ATF_REQUIRE(uselocale(l1) != NULL); 81 check_lparts(loc1); 82 83 freelocale(l1); 84 freelocale(l2); 85 } 86 87 /* 88 * PR 255646, 269375: Check that newlocale()/uselocale() used to switch between 89 * C, POSIX, and C.UTF-8 locales (and only these) do not stomp on other locale 90 * contents (collate part specifically). 91 * The issue is cosmetic only as all three have empty collate parts, but we need 92 * to correctly report the one in use in any case. 93 */ 94 95 ATF_TC_WITHOUT_HEAD(newlocale_c_posix_cu8_test); 96 ATF_TC_BODY(newlocale_c_posix_cu8_test, tc) 97 { 98 do_locale_switch("C", "POSIX"); 99 do_locale_switch("C", "C.UTF-8"); 100 do_locale_switch("POSIX", "C"); 101 do_locale_switch("POSIX", "C.UTF-8"); 102 do_locale_switch("C.UTF-8", "C"); 103 do_locale_switch("C.UTF-8", "POSIX"); 104 } 105 106 ATF_TP_ADD_TCS(tp) 107 { 108 ATF_TP_ADD_TC(tp, newlocale_c_posix_cu8_test); 109 110 return (atf_no_error()); 111 } 112