Home | History | Annotate | Line # | Download | only in gen
      1 /*	$NetBSD: t_ctype.c,v 1.12 2025/09/15 00:11:55 riastradh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2025 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /*
     30  * Tests for the ctype(3) character classification macros.
     31  *
     32  * NOTE: These tests intentionally trigger undefined behaviour by
     33  * passing int values to the ctype(3) functions which are neither EOF
     34  * nor representable by unsigned char.  The purpose is to verify
     35  * NetBSD's intentional trapping of this undefined behaviour -- or
     36  * intentional allowing of this undefined behaviour, when the
     37  * environment variable LIBC_ALLOWCTYPEABUSE is set.
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __RCSID("$NetBSD: t_ctype.c,v 1.12 2025/09/15 00:11:55 riastradh Exp $");
     42 
     43 #include <sys/wait.h>
     44 
     45 #include <atf-c.h>
     46 #include <ctype.h>
     47 #include <locale.h>
     48 #include <limits.h>
     49 #include <setjmp.h>
     50 #include <signal.h>
     51 #include <stdio.h>
     52 #include <unistd.h>
     53 
     54 #include "h_macros.h"
     55 
     56 #ifdef __CHAR_UNSIGNED__
     57 enum { CHAR_UNSIGNED = 1 };
     58 #else
     59 enum { CHAR_UNSIGNED = 0 };
     60 #endif
     61 
     62 /*
     63  * libc has a guard page for the LC_CTYPE=C ctype(3) tables only on
     64  * some platforms.  We skip it if char is unsigned (in which case the
     65  * common kind of ctype(3) abuse is unlikely).  We also skip it in
     66  * static builds -- this is determined in the Makefile.
     67  */
     68 #ifndef _CTYPE_GUARD_PAGE
     69 #  ifdef __CHAR_UNSIGNED__
     70 #    define	_CTYPE_GUARD_PAGE	0
     71 #  else
     72 #    define	_CTYPE_GUARD_PAGE	1
     73 #  endif
     74 #endif
     75 
     76 static const char *const locales[] = { "C.UTF-8", "fr_FR.ISO8859-1", "C" };
     77 
     78 static int isalpha_wrapper(int ch) { return isalpha(ch); }
     79 static int isupper_wrapper(int ch) { return isupper(ch); }
     80 static int islower_wrapper(int ch) { return islower(ch); }
     81 static int isdigit_wrapper(int ch) { return isdigit(ch); }
     82 static int isxdigit_wrapper(int ch) { return isxdigit(ch); }
     83 static int isalnum_wrapper(int ch) { return isalnum(ch); }
     84 static int isspace_wrapper(int ch) { return isspace(ch); }
     85 static int ispunct_wrapper(int ch) { return ispunct(ch); }
     86 static int isprint_wrapper(int ch) { return isprint(ch); }
     87 static int isgraph_wrapper(int ch) { return isgraph(ch); }
     88 static int iscntrl_wrapper(int ch) { return iscntrl(ch); }
     89 static int isblank_wrapper(int ch) { return isblank(ch); }
     90 static int toupper_wrapper(int ch) { return toupper(ch); }
     91 static int tolower_wrapper(int ch) { return tolower(ch); }
     92 
     93 jmp_buf env;
     94 
     95 static void
     96 handle_signal(int signo)
     97 {
     98 
     99 	longjmp(env, 1);
    100 }
    101 
    102 static void
    103 test_abuse(const char *name, int (*ctypefn)(int))
    104 {
    105 	volatile int ch;	/* for longjmp */
    106 
    107 	for (ch = CHAR_MIN; ch < 0; ch++) {
    108 		volatile int result;
    109 
    110 		if (ch == EOF)
    111 			continue;
    112 		ATF_REQUIRE_MSG(ch != (int)(unsigned char)ch, "ch=%d", ch);
    113 		if (setjmp(env) == 0) {
    114 			REQUIRE_LIBC(signal(SIGABRT, &handle_signal), SIG_ERR);
    115 			REQUIRE_LIBC(signal(SIGSEGV, &handle_signal), SIG_ERR);
    116 			result = (*ctypefn)(ch);
    117 			REQUIRE_LIBC(signal(SIGABRT, SIG_DFL), SIG_ERR);
    118 			REQUIRE_LIBC(signal(SIGSEGV, SIG_DFL), SIG_ERR);
    119 			atf_tc_fail_nonfatal("%s failed to detect invalid %d,"
    120 			    " returned %d",
    121 			    name, ch, result);
    122 		} else {
    123 			REQUIRE_LIBC(signal(SIGABRT, SIG_DFL), SIG_ERR);
    124 			REQUIRE_LIBC(signal(SIGSEGV, SIG_DFL), SIG_ERR);
    125 		}
    126 	}
    127 
    128 	for (; ch <= CHAR_MAX; ch++)
    129 		ATF_REQUIRE_MSG(ch == (int)(unsigned char)ch, "ch=%d", ch);
    130 }
    131 
    132 static void
    133 test_abuse_in_locales(const char *name, int (*ctypefn)(int), bool macro)
    134 {
    135 	size_t i;
    136 
    137 	for (i = 0; i < __arraycount(locales); i++) {
    138 		char buf[128];
    139 
    140 		if (!_CTYPE_GUARD_PAGE && macro &&
    141 		    strcmp(locales[i], "C") == 0) {
    142 			fprintf(stderr, "skip LC_CTYPE=C ctype(3) abuse --"
    143 			    " no libc guard page on this platform\n");
    144 		}
    145 
    146 		ATF_REQUIRE_MSG(setlocale(LC_CTYPE, locales[i]) != NULL,
    147 		    "locales[i]=%s", locales[i]);
    148 		snprintf(buf, sizeof(buf), "[%s]%s", locales[i], name);
    149 		test_abuse(buf, ctypefn);
    150 	}
    151 }
    152 
    153 static void
    154 test_use(const char *name, int (*ctypefn)(int))
    155 {
    156 	volatile int ch;	/* for longjmp */
    157 
    158 	for (ch = EOF; ch <= CHAR_MAX; ch = (ch == EOF ? 0 : ch + 1)) {
    159 		volatile int result;
    160 
    161 		if (setjmp(env) == 0) {
    162 			REQUIRE_LIBC(signal(SIGABRT, &handle_signal), SIG_ERR);
    163 			REQUIRE_LIBC(signal(SIGSEGV, &handle_signal), SIG_ERR);
    164 			result = (*ctypefn)(ch);
    165 			REQUIRE_LIBC(signal(SIGABRT, SIG_DFL), SIG_ERR);
    166 			REQUIRE_LIBC(signal(SIGSEGV, SIG_DFL), SIG_ERR);
    167 			(void)result;
    168 		} else {
    169 			REQUIRE_LIBC(signal(SIGABRT, SIG_DFL), SIG_ERR);
    170 			REQUIRE_LIBC(signal(SIGSEGV, SIG_DFL), SIG_ERR);
    171 			atf_tc_fail_nonfatal("%s(%d) raised SIGSEGV",
    172 			    name, ch);
    173 		}
    174 	}
    175 }
    176 
    177 static void
    178 test_isalpha_locale(const char *L, int (*ctypefn)(int))
    179 {
    180 
    181 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    182 	test_use("isalpha", ctypefn);
    183 	ATF_CHECK(!(*ctypefn)(EOF));
    184 }
    185 
    186 static void
    187 test_isupper_locale(const char *L, int (*ctypefn)(int))
    188 {
    189 
    190 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    191 	test_use("isupper", ctypefn);
    192 	ATF_CHECK(!(*ctypefn)(EOF));
    193 }
    194 
    195 static void
    196 test_islower_locale(const char *L, int (*ctypefn)(int))
    197 {
    198 
    199 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    200 	test_use("islower", ctypefn);
    201 	ATF_CHECK(!(*ctypefn)(EOF));
    202 }
    203 
    204 static void
    205 test_isdigit_locale(const char *L, int (*ctypefn)(int))
    206 {
    207 
    208 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    209 	test_use("isdigit", ctypefn);
    210 	ATF_CHECK(!(*ctypefn)(EOF));
    211 }
    212 
    213 static void
    214 test_isxdigit_locale(const char *L, int (*ctypefn)(int))
    215 {
    216 
    217 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    218 	test_use("isxdigit", ctypefn);
    219 	ATF_CHECK(!(*ctypefn)(EOF));
    220 }
    221 
    222 static void
    223 test_isalnum_locale(const char *L, int (*ctypefn)(int))
    224 {
    225 
    226 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    227 	test_use("isalnum", ctypefn);
    228 	ATF_CHECK(!(*ctypefn)(EOF));
    229 }
    230 
    231 static void
    232 test_isspace_locale(const char *L, int (*ctypefn)(int))
    233 {
    234 
    235 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    236 	test_use("isspace", ctypefn);
    237 	ATF_CHECK(!(*ctypefn)(EOF));
    238 }
    239 
    240 static void
    241 test_ispunct_locale(const char *L, int (*ctypefn)(int))
    242 {
    243 
    244 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    245 	test_use("ispunct", ctypefn);
    246 	ATF_CHECK(!(*ctypefn)(EOF));
    247 }
    248 
    249 static void
    250 test_isprint_locale(const char *L, int (*ctypefn)(int))
    251 {
    252 
    253 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    254 	test_use("isprint", ctypefn);
    255 	ATF_CHECK(!(*ctypefn)(EOF));
    256 }
    257 
    258 static void
    259 test_isgraph_locale(const char *L, int (*ctypefn)(int))
    260 {
    261 
    262 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    263 	test_use("isgraph", ctypefn);
    264 	ATF_CHECK(!(*ctypefn)(EOF));
    265 }
    266 
    267 static void
    268 test_iscntrl_locale(const char *L, int (*ctypefn)(int))
    269 {
    270 
    271 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    272 	test_use("iscntrl", ctypefn);
    273 	ATF_CHECK(!(*ctypefn)(EOF));
    274 }
    275 
    276 static void
    277 test_isblank_locale(const char *L, int (*ctypefn)(int))
    278 {
    279 
    280 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    281 	test_use("isblank", ctypefn);
    282 	ATF_CHECK(!(*ctypefn)(EOF));
    283 }
    284 
    285 static void
    286 test_toupper_locale(const char *L, int (*ctypefn)(int))
    287 {
    288 	int result;
    289 
    290 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    291 	test_use("toupper", ctypefn);
    292 	ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF,
    293 	    "result=%d, expected EOF=%d", result, EOF);
    294 }
    295 
    296 static void
    297 test_tolower_locale(const char *L, int (*ctypefn)(int))
    298 {
    299 	int result;
    300 
    301 	ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L);
    302 	test_use("tolower", ctypefn);
    303 	ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF,
    304 	    "result=%d, expected EOF=%d", result, EOF);
    305 }
    306 
    307 static void
    308 test_isalpha_c(int (*ctypefn)(int))
    309 {
    310 	int ch;
    311 
    312 	ATF_CHECK(!(*ctypefn)(EOF));
    313 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    314 		switch (ch) {
    315 		case 'a': case 'A':
    316 		case 'b': case 'B':
    317 		case 'c': case 'C':
    318 		case 'd': case 'D':
    319 		case 'e': case 'E':
    320 		case 'f': case 'F':
    321 		case 'g': case 'G':
    322 		case 'h': case 'H':
    323 		case 'i': case 'I':
    324 		case 'j': case 'J':
    325 		case 'k': case 'K':
    326 		case 'l': case 'L':
    327 		case 'm': case 'M':
    328 		case 'n': case 'N':
    329 		case 'o': case 'O':
    330 		case 'p': case 'P':
    331 		case 'q': case 'Q':
    332 		case 'r': case 'R':
    333 		case 's': case 'S':
    334 		case 't': case 'T':
    335 		case 'u': case 'U':
    336 		case 'v': case 'V':
    337 		case 'w': case 'W':
    338 		case 'x': case 'X':
    339 		case 'y': case 'Y':
    340 		case 'z': case 'Z':
    341 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    342 			break;
    343 		default:
    344 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    345 			break;
    346 		}
    347 	}
    348 }
    349 
    350 static void
    351 test_isupper_c(int (*ctypefn)(int))
    352 {
    353 	int ch;
    354 
    355 	ATF_CHECK(!(*ctypefn)(EOF));
    356 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    357 		switch (ch) {
    358 		case 'A':
    359 		case 'B':
    360 		case 'C':
    361 		case 'D':
    362 		case 'E':
    363 		case 'F':
    364 		case 'G':
    365 		case 'H':
    366 		case 'I':
    367 		case 'J':
    368 		case 'K':
    369 		case 'L':
    370 		case 'M':
    371 		case 'N':
    372 		case 'O':
    373 		case 'P':
    374 		case 'Q':
    375 		case 'R':
    376 		case 'S':
    377 		case 'T':
    378 		case 'U':
    379 		case 'V':
    380 		case 'W':
    381 		case 'X':
    382 		case 'Y':
    383 		case 'Z':
    384 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    385 			break;
    386 		default:
    387 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    388 			break;
    389 		}
    390 	}
    391 }
    392 
    393 static void
    394 test_islower_c(int (*ctypefn)(int))
    395 {
    396 	int ch;
    397 
    398 	ATF_CHECK(!(*ctypefn)(EOF));
    399 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    400 		switch (ch) {
    401 		case 'a':
    402 		case 'b':
    403 		case 'c':
    404 		case 'd':
    405 		case 'e':
    406 		case 'f':
    407 		case 'g':
    408 		case 'h':
    409 		case 'i':
    410 		case 'j':
    411 		case 'k':
    412 		case 'l':
    413 		case 'm':
    414 		case 'n':
    415 		case 'o':
    416 		case 'p':
    417 		case 'q':
    418 		case 'r':
    419 		case 's':
    420 		case 't':
    421 		case 'u':
    422 		case 'v':
    423 		case 'w':
    424 		case 'x':
    425 		case 'y':
    426 		case 'z':
    427 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    428 			break;
    429 		default:
    430 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    431 			break;
    432 		}
    433 	}
    434 }
    435 
    436 static void
    437 test_isdigit_c(int (*ctypefn)(int))
    438 {
    439 	int ch;
    440 
    441 	ATF_CHECK(!(*ctypefn)(EOF));
    442 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    443 		switch (ch) {
    444 		case '0':
    445 		case '1':
    446 		case '2':
    447 		case '3':
    448 		case '4':
    449 		case '5':
    450 		case '6':
    451 		case '7':
    452 		case '8':
    453 		case '9':
    454 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    455 			break;
    456 		default:
    457 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    458 			break;
    459 		}
    460 	}
    461 }
    462 
    463 static void
    464 test_isxdigit_c(int (*ctypefn)(int))
    465 {
    466 	int ch;
    467 
    468 	ATF_CHECK(!(*ctypefn)(EOF));
    469 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    470 		switch (ch) {
    471 		case '0':
    472 		case '1':
    473 		case '2':
    474 		case '3':
    475 		case '4':
    476 		case '5':
    477 		case '6':
    478 		case '7':
    479 		case '8':
    480 		case '9':
    481 		case 'a': case 'A':
    482 		case 'b': case 'B':
    483 		case 'c': case 'C':
    484 		case 'd': case 'D':
    485 		case 'e': case 'E':
    486 		case 'f': case 'F':
    487 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    488 			break;
    489 		default:
    490 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    491 			break;
    492 		}
    493 	}
    494 }
    495 
    496 static void
    497 test_isalnum_c(int (*ctypefn)(int))
    498 {
    499 	int ch;
    500 
    501 	ATF_CHECK(!(*ctypefn)(EOF));
    502 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    503 		switch (ch) {
    504 		case 'a': case 'A':
    505 		case 'b': case 'B':
    506 		case 'c': case 'C':
    507 		case 'd': case 'D':
    508 		case 'e': case 'E':
    509 		case 'f': case 'F':
    510 		case 'g': case 'G':
    511 		case 'h': case 'H':
    512 		case 'i': case 'I':
    513 		case 'j': case 'J':
    514 		case 'k': case 'K':
    515 		case 'l': case 'L':
    516 		case 'm': case 'M':
    517 		case 'n': case 'N':
    518 		case 'o': case 'O':
    519 		case 'p': case 'P':
    520 		case 'q': case 'Q':
    521 		case 'r': case 'R':
    522 		case 's': case 'S':
    523 		case 't': case 'T':
    524 		case 'u': case 'U':
    525 		case 'v': case 'V':
    526 		case 'w': case 'W':
    527 		case 'x': case 'X':
    528 		case 'y': case 'Y':
    529 		case 'z': case 'Z':
    530 		case '0':
    531 		case '1':
    532 		case '2':
    533 		case '3':
    534 		case '4':
    535 		case '5':
    536 		case '6':
    537 		case '7':
    538 		case '8':
    539 		case '9':
    540 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    541 			break;
    542 		default:
    543 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    544 			break;
    545 		}
    546 	}
    547 }
    548 
    549 static void
    550 test_isspace_c(int (*ctypefn)(int))
    551 {
    552 	int ch;
    553 
    554 	ATF_CHECK(!(*ctypefn)(EOF));
    555 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    556 		switch (ch) {
    557 		case ' ':
    558 		case '\f':
    559 		case '\n':
    560 		case '\r':
    561 		case '\t':
    562 		case '\v':
    563 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    564 			break;
    565 		default:
    566 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    567 			break;
    568 		}
    569 	}
    570 }
    571 
    572 static void
    573 test_ispunct_c(int (*ctypefn)(int))
    574 {
    575 	int ch;
    576 
    577 	ATF_CHECK(!(*ctypefn)(EOF));
    578 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    579 		switch (ch) {
    580 		default:
    581 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    582 			break;
    583 		case 0 ... 0x1f:
    584 		case 0x20:	/* space is printing but not punctuation */
    585 		case 0x7f:
    586 		case 0x80 ... 0xff:
    587 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    588 			break;
    589 		case 'a': case 'A':
    590 		case 'b': case 'B':
    591 		case 'c': case 'C':
    592 		case 'd': case 'D':
    593 		case 'e': case 'E':
    594 		case 'f': case 'F':
    595 		case 'g': case 'G':
    596 		case 'h': case 'H':
    597 		case 'i': case 'I':
    598 		case 'j': case 'J':
    599 		case 'k': case 'K':
    600 		case 'l': case 'L':
    601 		case 'm': case 'M':
    602 		case 'n': case 'N':
    603 		case 'o': case 'O':
    604 		case 'p': case 'P':
    605 		case 'q': case 'Q':
    606 		case 'r': case 'R':
    607 		case 's': case 'S':
    608 		case 't': case 'T':
    609 		case 'u': case 'U':
    610 		case 'v': case 'V':
    611 		case 'w': case 'W':
    612 		case 'x': case 'X':
    613 		case 'y': case 'Y':
    614 		case 'z': case 'Z':
    615 		case '0':
    616 		case '1':
    617 		case '2':
    618 		case '3':
    619 		case '4':
    620 		case '5':
    621 		case '6':
    622 		case '7':
    623 		case '8':
    624 		case '9':
    625 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    626 			break;
    627 		}
    628 	}
    629 }
    630 
    631 static void
    632 test_isprint_c(int (*ctypefn)(int))
    633 {
    634 	int ch;
    635 
    636 	ATF_CHECK(!(*ctypefn)(EOF));
    637 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    638 		switch (ch) {
    639 		case 0x20:	/* space is printing but not graphic */
    640 		default:
    641 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    642 			break;
    643 		case 0 ... 0x1f:
    644 		case 0x7f:
    645 		case 0x80 ... 0xff:
    646 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    647 			break;
    648 		}
    649 	}
    650 }
    651 
    652 static void
    653 test_isgraph_c(int (*ctypefn)(int))
    654 {
    655 	int ch;
    656 
    657 	ATF_CHECK(!(*ctypefn)(EOF));
    658 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    659 		switch (ch) {
    660 		default:
    661 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    662 			break;
    663 		case 0 ... 0x1f:
    664 		case 0x20:	/* space is printing but not graphic */
    665 		case 0x7f:
    666 		case 0x80 ... 0xff:
    667 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    668 			break;
    669 		}
    670 	}
    671 }
    672 
    673 static void
    674 test_iscntrl_c(int (*ctypefn)(int))
    675 {
    676 	int ch;
    677 
    678 	ATF_CHECK(!(*ctypefn)(EOF));
    679 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    680 		switch (ch) {
    681 		case 0 ... 0x1f:
    682 		case 0x7f:
    683 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    684 			break;
    685 		default:
    686 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    687 			break;
    688 		}
    689 	}
    690 }
    691 
    692 static void
    693 test_isblank_c(int (*ctypefn)(int))
    694 {
    695 	int ch;
    696 
    697 	ATF_CHECK(!(*ctypefn)(EOF));
    698 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    699 		switch (ch) {
    700 		case ' ':
    701 		case '\t':
    702 			ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch);
    703 			break;
    704 		default:
    705 			ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch);
    706 			break;
    707 		}
    708 	}
    709 }
    710 
    711 static void
    712 test_toupper_c(int (*ctypefn)(int))
    713 {
    714 	int ch, result, expected;
    715 
    716 	ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF,
    717 	    "result=%d, expected EOF=%d", result, EOF);
    718 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    719 		switch (ch) {
    720 		case 'a': case 'A': expected = 'A'; break;
    721 		case 'b': case 'B': expected = 'B'; break;
    722 		case 'c': case 'C': expected = 'C'; break;
    723 		case 'd': case 'D': expected = 'D'; break;
    724 		case 'e': case 'E': expected = 'E'; break;
    725 		case 'f': case 'F': expected = 'F'; break;
    726 		case 'g': case 'G': expected = 'G'; break;
    727 		case 'h': case 'H': expected = 'H'; break;
    728 		case 'i': case 'I': expected = 'I'; break;
    729 		case 'j': case 'J': expected = 'J'; break;
    730 		case 'k': case 'K': expected = 'K'; break;
    731 		case 'l': case 'L': expected = 'L'; break;
    732 		case 'm': case 'M': expected = 'M'; break;
    733 		case 'n': case 'N': expected = 'N'; break;
    734 		case 'o': case 'O': expected = 'O'; break;
    735 		case 'p': case 'P': expected = 'P'; break;
    736 		case 'q': case 'Q': expected = 'Q'; break;
    737 		case 'r': case 'R': expected = 'R'; break;
    738 		case 's': case 'S': expected = 'S'; break;
    739 		case 't': case 'T': expected = 'T'; break;
    740 		case 'u': case 'U': expected = 'U'; break;
    741 		case 'v': case 'V': expected = 'V'; break;
    742 		case 'w': case 'W': expected = 'W'; break;
    743 		case 'x': case 'X': expected = 'X'; break;
    744 		case 'y': case 'Y': expected = 'Y'; break;
    745 		case 'z': case 'Z': expected = 'Z'; break;
    746 		default:
    747 			expected = ch;
    748 			break;
    749 		}
    750 		ATF_CHECK_MSG((result = (*ctypefn)(ch)) == expected,
    751 		    "result=%d expected=%d", result, expected);
    752 	}
    753 }
    754 
    755 static void
    756 test_tolower_c(int (*ctypefn)(int))
    757 {
    758 	int ch, result, expected;
    759 
    760 	ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF,
    761 	    "result=%d, expected EOF=%d", result, EOF);
    762 	for (ch = 0; ch <= UCHAR_MAX; ch++) {
    763 		switch (ch) {
    764 		case 'a': case 'A': expected = 'a'; break;
    765 		case 'b': case 'B': expected = 'b'; break;
    766 		case 'c': case 'C': expected = 'c'; break;
    767 		case 'd': case 'D': expected = 'd'; break;
    768 		case 'e': case 'E': expected = 'e'; break;
    769 		case 'f': case 'F': expected = 'f'; break;
    770 		case 'g': case 'G': expected = 'g'; break;
    771 		case 'h': case 'H': expected = 'h'; break;
    772 		case 'i': case 'I': expected = 'i'; break;
    773 		case 'j': case 'J': expected = 'j'; break;
    774 		case 'k': case 'K': expected = 'k'; break;
    775 		case 'l': case 'L': expected = 'l'; break;
    776 		case 'm': case 'M': expected = 'm'; break;
    777 		case 'n': case 'N': expected = 'n'; break;
    778 		case 'o': case 'O': expected = 'o'; break;
    779 		case 'p': case 'P': expected = 'p'; break;
    780 		case 'q': case 'Q': expected = 'q'; break;
    781 		case 'r': case 'R': expected = 'r'; break;
    782 		case 's': case 'S': expected = 's'; break;
    783 		case 't': case 'T': expected = 't'; break;
    784 		case 'u': case 'U': expected = 'u'; break;
    785 		case 'v': case 'V': expected = 'v'; break;
    786 		case 'w': case 'W': expected = 'w'; break;
    787 		case 'x': case 'X': expected = 'x'; break;
    788 		case 'y': case 'Y': expected = 'y'; break;
    789 		case 'z': case 'Z': expected = 'z'; break;
    790 		default:
    791 			expected = ch;
    792 			break;
    793 		}
    794 		ATF_CHECK_MSG((result = (*ctypefn)(ch)) == expected,
    795 		    "result=%d expected=%d", result, expected);
    796 	}
    797 }
    798 
    799 extern char **environ;
    800 
    801 static void
    802 test_abuse_override(const struct atf_tc *tc, const char *fn, const char *mode,
    803     const char *locale)
    804 {
    805 	char h_ctype_abuse[PATH_MAX];
    806 	pid_t pid;
    807 	int status;
    808 
    809 	RL(snprintf(h_ctype_abuse, sizeof(h_ctype_abuse), "%s/h_ctype_abuse",
    810 		atf_tc_get_config_var(tc, "srcdir")));
    811 
    812 	RL(setenv("LIBC_ALLOWCTYPEABUSE", "", 1));
    813 
    814 	RL(pid = vfork());
    815 	if (pid == 0) {		/* child */
    816 		char *const argv[] = {
    817 			h_ctype_abuse,
    818 			__UNCONST(fn),
    819 			__UNCONST(mode),
    820 			__UNCONST(locale),
    821 			NULL,
    822 		};
    823 
    824 		if (execve(argv[0], argv, environ) == -1)
    825 			_exit(1);
    826 		_exit(2);
    827 	}
    828 
    829 	RL(waitpid(pid, &status, 0));
    830 	if (WIFSIGNALED(status)) {
    831 		atf_tc_fail_nonfatal("child exited on signal %d (%s)",
    832 		    WTERMSIG(status), strsignal(WTERMSIG(status)));
    833 	} else if (!WIFEXITED(status)) {
    834 		atf_tc_fail_nonfatal("child exited status=0x%x", status);
    835 	} else {
    836 		ATF_CHECK_MSG(WEXITSTATUS(status) == 0,
    837 		    "child exited with code %d",
    838 		    WEXITSTATUS(status));
    839 	}
    840 }
    841 
    842 static void
    843 test_abuse_override_in_locales(const struct atf_tc *tc, const char *fn,
    844     const char *mode)
    845 {
    846 	size_t i;
    847 
    848 	for (i = 0; i < __arraycount(locales); i++) {
    849 		fprintf(stderr, "# locale %s\n", locales[i]);
    850 		test_abuse_override(tc, fn, mode, locales[i]);
    851 	}
    852 }
    853 
    854 #define	ADD_TEST_ABUSE(TP, FN) do					      \
    855 {									      \
    856 	ATF_TP_ADD_TC(TP, abuse_##FN##_macro_c);			      \
    857 	ATF_TP_ADD_TC(TP, abuse_##FN##_function_c);			      \
    858 	ATF_TP_ADD_TC(TP, abuse_##FN##_macro_locale);			      \
    859 	ATF_TP_ADD_TC(TP, abuse_##FN##_function_locale);		      \
    860 } while (0)
    861 
    862 #define	DEF_TEST_ABUSE(FN)						      \
    863 ATF_TC(abuse_##FN##_macro_c);						      \
    864 ATF_TC_HEAD(abuse_##FN##_macro_c, tc)					      \
    865 {									      \
    866 	atf_tc_set_md_var(tc, "descr",					      \
    867 	    "Test abusing "#FN" macro with default LC_CTYPE=C");	      \
    868 }									      \
    869 ATF_TC_BODY(abuse_##FN##_macro_c, tc)					      \
    870 {									      \
    871 	if (CHAR_UNSIGNED) {						      \
    872 		atf_tc_skip("runtime ctype(3) abuse is impossible with"	      \
    873 		    " unsigned char");					      \
    874 	}								      \
    875 	if (!_CTYPE_GUARD_PAGE)						      \
    876 		atf_tc_skip("no LC_CTYPE=C guard page on this platform");     \
    877 	test_abuse(#FN, &FN##_wrapper);					      \
    878 }									      \
    879 ATF_TC(abuse_##FN##_function_c);					      \
    880 ATF_TC_HEAD(abuse_##FN##_function_c, tc)				      \
    881 {									      \
    882 	atf_tc_set_md_var(tc, "descr",					      \
    883 	    "Test abusing "#FN" function with default LC_CTYPE=C");	      \
    884 }									      \
    885 ATF_TC_BODY(abuse_##FN##_function_c, tc)				      \
    886 {									      \
    887 	if (CHAR_UNSIGNED) {						      \
    888 		atf_tc_skip("runtime ctype(3) abuse is impossible with"	      \
    889 		    " unsigned char");					      \
    890 	}								      \
    891 	if (!_CTYPE_GUARD_PAGE)						      \
    892 		atf_tc_skip("no LC_CTYPE=C guard page on this platform");     \
    893 	test_abuse(#FN, &FN);						      \
    894 }									      \
    895 ATF_TC(abuse_##FN##_macro_locale);					      \
    896 ATF_TC_HEAD(abuse_##FN##_macro_locale, tc)				      \
    897 {									      \
    898 	atf_tc_set_md_var(tc, "descr",					      \
    899 	    "Test abusing "#FN" macro with locales");			      \
    900 }									      \
    901 ATF_TC_BODY(abuse_##FN##_macro_locale, tc)				      \
    902 {									      \
    903 	if (CHAR_UNSIGNED) {						      \
    904 		atf_tc_skip("runtime ctype(3) abuse is impossible with"	      \
    905 		    " unsigned char");					      \
    906 	}								      \
    907 	test_abuse_in_locales(#FN, &FN##_wrapper, /*macro*/true);	      \
    908 }									      \
    909 ATF_TC(abuse_##FN##_function_locale);					      \
    910 ATF_TC_HEAD(abuse_##FN##_function_locale, tc)				      \
    911 {									      \
    912 	atf_tc_set_md_var(tc, "descr",					      \
    913 	    "Test abusing "#FN" function with locales");		      \
    914 }									      \
    915 ATF_TC_BODY(abuse_##FN##_function_locale, tc)				      \
    916 {									      \
    917 	if (CHAR_UNSIGNED) {						      \
    918 		atf_tc_skip("runtime ctype(3) abuse is impossible with"	      \
    919 		    " unsigned char");					      \
    920 	}								      \
    921 	test_abuse_in_locales(#FN, &FN, /*macro*/false);		      \
    922 }
    923 
    924 #define	ADD_TEST_ABUSE_OVERRIDE(TP, FN) do				      \
    925 {									      \
    926 	ATF_TP_ADD_TC(TP, abuse_override_##FN##_macro_c);		      \
    927 	ATF_TP_ADD_TC(TP, abuse_override_##FN##_function_c);		      \
    928 	ATF_TP_ADD_TC(TP, abuse_override_##FN##_macro_locale);		      \
    929 	ATF_TP_ADD_TC(TP, abuse_override_##FN##_function_locale);	      \
    930 } while (0)
    931 
    932 #define	DEF_TEST_ABUSE_OVERRIDE(FN)					      \
    933 ATF_TC(abuse_override_##FN##_macro_c);					      \
    934 ATF_TC_HEAD(abuse_override_##FN##_macro_c, tc)				      \
    935 {									      \
    936 	atf_tc_set_md_var(tc, "descr",					      \
    937 	    "Test allowing abuse of "#FN" macro with default LC_CTYPE=C");    \
    938 }									      \
    939 ATF_TC_BODY(abuse_override_##FN##_macro_c, tc)				      \
    940 {									      \
    941 	test_abuse_override(tc, #FN, "macro", NULL);			      \
    942 }									      \
    943 ATF_TC(abuse_override_##FN##_function_c);				      \
    944 ATF_TC_HEAD(abuse_override_##FN##_function_c, tc)			      \
    945 {									      \
    946 	atf_tc_set_md_var(tc, "descr",					      \
    947 	    "Test allowing abuse "#FN" function with default LC_CTYPE=C");    \
    948 }									      \
    949 ATF_TC_BODY(abuse_override_##FN##_function_c, tc)			      \
    950 {									      \
    951 	test_abuse_override(tc, #FN, "function", NULL);			      \
    952 }									      \
    953 ATF_TC(abuse_override_##FN##_macro_locale);				      \
    954 ATF_TC_HEAD(abuse_override_##FN##_macro_locale, tc)			      \
    955 {									      \
    956 	atf_tc_set_md_var(tc, "descr",					      \
    957 	    "Test allowing abuse of "#FN" macro with locales");		      \
    958 }									      \
    959 ATF_TC_BODY(abuse_override_##FN##_macro_locale, tc)			      \
    960 {									      \
    961 	test_abuse_override_in_locales(tc, #FN, "macro");		      \
    962 }									      \
    963 ATF_TC(abuse_override_##FN##_function_locale);				      \
    964 ATF_TC_HEAD(abuse_override_##FN##_function_locale, tc)			      \
    965 {									      \
    966 	atf_tc_set_md_var(tc, "descr",					      \
    967 	    "Test allowing abuse of "#FN" function with locales");	      \
    968 }									      \
    969 ATF_TC_BODY(abuse_override_##FN##_function_locale, tc)			      \
    970 {									      \
    971 	test_abuse_override_in_locales(tc, #FN, "function");		      \
    972 }
    973 
    974 #define	ADD_TEST_USE(TP, FN) do						      \
    975 {									      \
    976 	ATF_TP_ADD_TC(TP, FN##_macro_c);				      \
    977 	ATF_TP_ADD_TC(TP, FN##_function_c);				      \
    978 	ATF_TP_ADD_TC(TP, FN##_macro_locale);				      \
    979 	ATF_TP_ADD_TC(TP, FN##_function_locale);			      \
    980 } while (0)
    981 
    982 #define	DEF_TEST_USE(FN)						      \
    983 ATF_TC(FN##_macro_c);							      \
    984 ATF_TC_HEAD(FN##_macro_c, tc)						      \
    985 {									      \
    986 	atf_tc_set_md_var(tc, "descr",					      \
    987 	    "Test "#FN" macro with default LC_CTYPE=C");		      \
    988 }									      \
    989 ATF_TC_BODY(FN##_macro_c, tc)						      \
    990 {									      \
    991 	test_##FN##_c(&FN##_wrapper);					      \
    992 }									      \
    993 ATF_TC(FN##_function_c);						      \
    994 ATF_TC_HEAD(FN##_function_c, tc)					      \
    995 {									      \
    996 	atf_tc_set_md_var(tc, "descr",					      \
    997 	    "Test "#FN" function with default LC_CTYPE=C");		      \
    998 }									      \
    999 ATF_TC_BODY(FN##_function_c, tc)					      \
   1000 {									      \
   1001 	test_##FN##_c(&FN);						      \
   1002 }									      \
   1003 ATF_TC(FN##_macro_locale);						      \
   1004 ATF_TC_HEAD(FN##_macro_locale, tc)					      \
   1005 {									      \
   1006 	atf_tc_set_md_var(tc, "descr",					      \
   1007 	    "Test "#FN" macro with locales");				      \
   1008 }									      \
   1009 ATF_TC_BODY(FN##_macro_locale, tc)					      \
   1010 {									      \
   1011 	size_t i;							      \
   1012 									      \
   1013 	for (i = 0; i < __arraycount(locales); i++)			      \
   1014 		test_##FN##_locale(locales[i], &FN##_wrapper);		      \
   1015 }									      \
   1016 ATF_TC(FN##_function_locale);						      \
   1017 ATF_TC_HEAD(FN##_function_locale, tc)					      \
   1018 {									      \
   1019 	atf_tc_set_md_var(tc, "descr",					      \
   1020 	    "Test "#FN" function with locales");			      \
   1021 }									      \
   1022 ATF_TC_BODY(FN##_function_locale, tc)					      \
   1023 {									      \
   1024 	size_t i;							      \
   1025 									      \
   1026 	for (i = 0; i < __arraycount(locales); i++)			      \
   1027 		test_##FN##_locale(locales[i], &FN);			      \
   1028 }
   1029 
   1030 DEF_TEST_ABUSE(isalpha)
   1031 DEF_TEST_ABUSE(isupper)
   1032 DEF_TEST_ABUSE(islower)
   1033 DEF_TEST_ABUSE(isdigit)
   1034 DEF_TEST_ABUSE(isxdigit)
   1035 DEF_TEST_ABUSE(isalnum)
   1036 DEF_TEST_ABUSE(isspace)
   1037 DEF_TEST_ABUSE(ispunct)
   1038 DEF_TEST_ABUSE(isprint)
   1039 DEF_TEST_ABUSE(isgraph)
   1040 DEF_TEST_ABUSE(iscntrl)
   1041 DEF_TEST_ABUSE(isblank)
   1042 DEF_TEST_ABUSE(toupper)
   1043 DEF_TEST_ABUSE(tolower)
   1044 
   1045 DEF_TEST_ABUSE_OVERRIDE(isalpha)
   1046 DEF_TEST_ABUSE_OVERRIDE(isupper)
   1047 DEF_TEST_ABUSE_OVERRIDE(islower)
   1048 DEF_TEST_ABUSE_OVERRIDE(isdigit)
   1049 DEF_TEST_ABUSE_OVERRIDE(isxdigit)
   1050 DEF_TEST_ABUSE_OVERRIDE(isalnum)
   1051 DEF_TEST_ABUSE_OVERRIDE(isspace)
   1052 DEF_TEST_ABUSE_OVERRIDE(ispunct)
   1053 DEF_TEST_ABUSE_OVERRIDE(isprint)
   1054 DEF_TEST_ABUSE_OVERRIDE(isgraph)
   1055 DEF_TEST_ABUSE_OVERRIDE(iscntrl)
   1056 DEF_TEST_ABUSE_OVERRIDE(isblank)
   1057 DEF_TEST_ABUSE_OVERRIDE(toupper)
   1058 DEF_TEST_ABUSE_OVERRIDE(tolower)
   1059 
   1060 DEF_TEST_USE(isalpha)
   1061 DEF_TEST_USE(isupper)
   1062 DEF_TEST_USE(islower)
   1063 DEF_TEST_USE(isdigit)
   1064 DEF_TEST_USE(isxdigit)
   1065 DEF_TEST_USE(isalnum)
   1066 DEF_TEST_USE(isspace)
   1067 DEF_TEST_USE(ispunct)
   1068 DEF_TEST_USE(isprint)
   1069 DEF_TEST_USE(isgraph)
   1070 DEF_TEST_USE(iscntrl)
   1071 DEF_TEST_USE(isblank)
   1072 DEF_TEST_USE(toupper)
   1073 DEF_TEST_USE(tolower)
   1074 
   1075 ATF_TC(eof_confusion_iso8859_1);
   1076 ATF_TC_HEAD(eof_confusion_iso8859_1, tc)
   1077 {
   1078 	atf_tc_set_md_var(tc, "descr",
   1079 	    "Test potential confusion with EOF in ISO-8859-1");
   1080 }
   1081 ATF_TC_BODY(eof_confusion_iso8859_1, tc)
   1082 {
   1083 	int ydots = 0xff;	/* , LATIN SMALL LETTER Y WITH DIAERESIS */
   1084 	int ch;
   1085 
   1086 	/*
   1087 	 * The LATIN SMALL LETTER Y WITH DIAERESIS code point 0xff in
   1088 	 * ISO-8859-1 is curious primarily because its bit pattern
   1089 	 * coincides with an 8-bit signed -1, which is to say, EOF as
   1090 	 * an 8-bit quantity; of course, for EOF, all of the is*
   1091 	 * functions are supposed to return false (as we test above).
   1092 	 * It also has the curious property that it lacks any
   1093 	 * corresponding uppercase code point in ISO-8859-1, so we
   1094 	 * can't distinguish it from EOF by tolower/toupper.
   1095 	 */
   1096 	ATF_REQUIRE(setlocale(LC_CTYPE, "fr_FR.ISO8859-1") != NULL);
   1097 	ATF_CHECK(isalpha(ydots));
   1098 	ATF_CHECK(!isupper(ydots));
   1099 	ATF_CHECK(islower(ydots));
   1100 	ATF_CHECK(!isdigit(ydots));
   1101 	ATF_CHECK(!isxdigit(ydots));
   1102 	ATF_CHECK(isalnum(ydots));
   1103 	ATF_CHECK(!isspace(ydots));
   1104 	ATF_CHECK(!ispunct(ydots));
   1105 	ATF_CHECK(isprint(ydots));
   1106 	ATF_CHECK(isgraph(ydots));
   1107 	ATF_CHECK(!iscntrl(ydots));
   1108 	ATF_CHECK(!isblank(ydots));
   1109 	ATF_CHECK_MSG((ch = toupper(ydots)) == ydots, "ch=0x%x", ch);
   1110 	ATF_CHECK_MSG((ch = tolower(ydots)) == ydots, "ch=0x%x", ch);
   1111 }
   1112 
   1113 ATF_TC(eof_confusion_koi8_u);
   1114 ATF_TC_HEAD(eof_confusion_koi8_u, tc)
   1115 {
   1116 	atf_tc_set_md_var(tc, "descr",
   1117 	    "Test potential confusion with EOF in KOI8-U");
   1118 }
   1119 ATF_TC_BODY(eof_confusion_koi8_u, tc)
   1120 {
   1121 	int Hard = 0xff;	/* , CYRILLIC CAPITAL LETTER HARD SIGN */
   1122 	int hard = 0xdf;	/* , CYRILLIC SMALL LETTER HARD SIGN */
   1123 	int ch;
   1124 
   1125 	/*
   1126 	 * The CYRILLIC CAPITAL LETTER HARD SIGN code point 0xff in
   1127 	 * KOI8-U (and KOI8-R) also coincides with the bit pattern of
   1128 	 * an 8-bit signed -1.  Unlike LATIN SMALL LETTER Y WITH
   1129 	 * DIAERESIS, it has a lowercase equivalent in KOI8-U.
   1130 	 */
   1131 	ATF_REQUIRE(setlocale(LC_CTYPE, "uk_UA.KOI8-U") != NULL);
   1132 	ATF_CHECK(isalpha(Hard));
   1133 	ATF_CHECK(isupper(Hard));
   1134 	ATF_CHECK(!islower(Hard));
   1135 	ATF_CHECK(!isdigit(Hard));
   1136 	ATF_CHECK(!isxdigit(Hard));
   1137 	ATF_CHECK(isalnum(Hard));
   1138 	ATF_CHECK(!isspace(Hard));
   1139 	ATF_CHECK(!ispunct(Hard));
   1140 	ATF_CHECK(isprint(Hard));
   1141 	ATF_CHECK(isgraph(Hard));
   1142 	ATF_CHECK(!iscntrl(Hard));
   1143 	ATF_CHECK(!isblank(Hard));
   1144 	ATF_CHECK_MSG((ch = toupper(Hard)) == Hard, "ch=0x%x", ch);
   1145 	ATF_CHECK_MSG((ch = tolower(Hard)) == hard, "ch=0x%x", ch);
   1146 }
   1147 
   1148 ATF_TC(eof_confusion_pt154);
   1149 ATF_TC_HEAD(eof_confusion_pt154, tc)
   1150 {
   1151 	atf_tc_set_md_var(tc, "descr",
   1152 	    "Test potential confusion with EOF in PT154");
   1153 }
   1154 ATF_TC_BODY(eof_confusion_pt154, tc)
   1155 {
   1156 	int ya = 0xff;		/* , CYRILLIC SMALL LETTER YA */
   1157 	int Ya = 0xdf;		/* , CYRILLIC CAPITAL LETTER YA */
   1158 	int ch;
   1159 
   1160 	/*
   1161 	 * The CYRILLIC SMALL LETTER YA code point 0xff in PT154 also
   1162 	 * coincides with the bit pattern of an 8-bit signed -1, and is
   1163 	 * lowercase with a corresponding uppercase code point in
   1164 	 * PT154.
   1165 	 */
   1166 	ATF_REQUIRE(setlocale(LC_CTYPE, "kk_KZ.PT154") != NULL);
   1167 	ATF_CHECK(isalpha(ya));
   1168 	ATF_CHECK(!isupper(ya));
   1169 	ATF_CHECK(islower(ya));
   1170 	ATF_CHECK(!isdigit(ya));
   1171 	ATF_CHECK(!isxdigit(ya));
   1172 	ATF_CHECK(isalnum(ya));
   1173 	ATF_CHECK(!isspace(ya));
   1174 	ATF_CHECK(!ispunct(ya));
   1175 	ATF_CHECK(isprint(ya));
   1176 	ATF_CHECK(isgraph(ya));
   1177 	ATF_CHECK(!iscntrl(ya));
   1178 	ATF_CHECK(!isblank(ya));
   1179 	ATF_CHECK_MSG((ch = toupper(ya)) == Ya, "ch=0x%x", ch);
   1180 	ATF_CHECK_MSG((ch = tolower(ya)) == ya, "ch=0x%x", ch);
   1181 }
   1182 
   1183 ATF_TP_ADD_TCS(tp)
   1184 {
   1185 
   1186 	ADD_TEST_ABUSE(tp, isalpha);
   1187 	ADD_TEST_ABUSE(tp, isupper);
   1188 	ADD_TEST_ABUSE(tp, islower);
   1189 	ADD_TEST_ABUSE(tp, isdigit);
   1190 	ADD_TEST_ABUSE(tp, isxdigit);
   1191 	ADD_TEST_ABUSE(tp, isalnum);
   1192 	ADD_TEST_ABUSE(tp, isspace);
   1193 	ADD_TEST_ABUSE(tp, ispunct);
   1194 	ADD_TEST_ABUSE(tp, isprint);
   1195 	ADD_TEST_ABUSE(tp, isgraph);
   1196 	ADD_TEST_ABUSE(tp, iscntrl);
   1197 	ADD_TEST_ABUSE(tp, isblank);
   1198 	ADD_TEST_ABUSE(tp, toupper);
   1199 	ADD_TEST_ABUSE(tp, tolower);
   1200 
   1201 	ADD_TEST_ABUSE_OVERRIDE(tp, isalpha);
   1202 	ADD_TEST_ABUSE_OVERRIDE(tp, isupper);
   1203 	ADD_TEST_ABUSE_OVERRIDE(tp, islower);
   1204 	ADD_TEST_ABUSE_OVERRIDE(tp, isdigit);
   1205 	ADD_TEST_ABUSE_OVERRIDE(tp, isxdigit);
   1206 	ADD_TEST_ABUSE_OVERRIDE(tp, isalnum);
   1207 	ADD_TEST_ABUSE_OVERRIDE(tp, isspace);
   1208 	ADD_TEST_ABUSE_OVERRIDE(tp, ispunct);
   1209 	ADD_TEST_ABUSE_OVERRIDE(tp, isprint);
   1210 	ADD_TEST_ABUSE_OVERRIDE(tp, isgraph);
   1211 	ADD_TEST_ABUSE_OVERRIDE(tp, iscntrl);
   1212 	ADD_TEST_ABUSE_OVERRIDE(tp, isblank);
   1213 	ADD_TEST_ABUSE_OVERRIDE(tp, toupper);
   1214 	ADD_TEST_ABUSE_OVERRIDE(tp, tolower);
   1215 
   1216 	ADD_TEST_USE(tp, isalpha);
   1217 	ADD_TEST_USE(tp, isupper);
   1218 	ADD_TEST_USE(tp, islower);
   1219 	ADD_TEST_USE(tp, isdigit);
   1220 	ADD_TEST_USE(tp, isxdigit);
   1221 	ADD_TEST_USE(tp, isalnum);
   1222 	ADD_TEST_USE(tp, isspace);
   1223 	ADD_TEST_USE(tp, ispunct);
   1224 	ADD_TEST_USE(tp, isprint);
   1225 	ADD_TEST_USE(tp, isgraph);
   1226 	ADD_TEST_USE(tp, iscntrl);
   1227 	ADD_TEST_USE(tp, isblank);
   1228 	ADD_TEST_USE(tp, toupper);
   1229 	ADD_TEST_USE(tp, tolower);
   1230 
   1231 	ATF_TP_ADD_TC(tp, eof_confusion_iso8859_1);
   1232 	ATF_TP_ADD_TC(tp, eof_confusion_koi8_u);
   1233 	ATF_TP_ADD_TC(tp, eof_confusion_pt154);
   1234 
   1235 	return atf_no_error();
   1236 }
   1237