From: Paul Eggert Date: Fri, 25 Sep 2015 07:01:10 +0000 (-0700) Subject: c-ctype: rewrite to use inline functions X-Git-Tag: v1.0~6947 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=43a090ce05f7046457be302ae4a17e83351968b0;p=gnulib.git c-ctype: rewrite to use inline functions This simplifies maintenance, since it makes for just one implementation of each function, letting the compiler have the fun of optimization. In practice this works well nowadays with GCC. E.g., c_isascii might need only three instructions even though the source code lists every ASCII character individually in a large switch statement. Also, fix some z/OS porting bugs reported by Daniel Richard G. in: http://lists.gnu.org/archive/html/bug-gnulib/2015-09/msg00037.html * NEWS: Document the API change. * lib/c-ctype.c: Drastically simplify, since this now just expands inline functions. * lib/c-ctype.h: Use _GL_INLINE_HEADER_BEGIN, _GL_INLINE_HEADER_END. (C_CTYPE_INLINE): New macro. (C_CTYPE_CONSECUTIVE_DIGITS, C_CTYPE_CONSECUTIVE_LOWERCASE) (C_CTYPE_CONSECUTIVE_UPPERCASE): Remove. Verify that either ASCII or EBCDIC is being used. (_C_CTYPE_SIGNED_EBCDIC, _C_CTYPE_CNTRL, _C_CTYPE_A_THRU_F_N) (_C_CTYPE_DIGIT_N, _C_CTYPE_LOWER_N, _C_CTYPE_UPPER_N) (_C_CTYPE_CASES, _C_CTYPE_A_THRU_F, _C_CTYPE_DIGIT, _C_CTYPE_LOWER) (_C_CTYPE_UPPER, _C_CTYPE_PUNCT_PLAIN): New private macros. (_C_CTYPE_CNTRL): In EBCDIC, '\x07' is a control, not '\xff'. (c_isalnum, c_isalpha, c_isascii, c_isblank, c_iscntrl, c_isdigit) (c_isgraph, c_islower, c_isprint, c_ispunct, c_isspace, c_isupper) (c_isxdigit, c_tolower, c_toupper): Now inline functions. (c_tolower, c_toupper): When converting, return the unsigned char, as that is what z/OS does. * lib/c-strcaseeq.h (CASEEQ): Simplify in the light of the removal of some c-ctype.h macros. * modules/c-ctype (Depends-on): Add extern-inline; remove verify. * tests/test-c-ctype.c (test_all): Fix test for c_toupper and c_tolower promotion to be compatible with z/OS. --- diff --git a/ChangeLog b/ChangeLog index 81a532692d..3768f3dd87 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +2015-09-25 Paul Eggert + + c-ctype: rewrite to use inline functions + This simplifies maintenance, since it makes for just one + implementation of each function, letting the compiler have the fun + of optimization. In practice this works well nowadays with GCC. + E.g., c_isascii might need only three instructions even though the + source code lists every ASCII character individually in a large + switch statement. + Also, fix some z/OS porting bugs reported by Daniel Richard G. in: + http://lists.gnu.org/archive/html/bug-gnulib/2015-09/msg00037.html + * NEWS: Document the API change. + * lib/c-ctype.c: Drastically simplify, since this now just expands + inline functions. + * lib/c-ctype.h: Use _GL_INLINE_HEADER_BEGIN, _GL_INLINE_HEADER_END. + (C_CTYPE_INLINE): New macro. + (C_CTYPE_CONSECUTIVE_DIGITS, C_CTYPE_CONSECUTIVE_LOWERCASE) + (C_CTYPE_CONSECUTIVE_UPPERCASE): Remove. + Verify that either ASCII or EBCDIC is being used. + (_C_CTYPE_SIGNED_EBCDIC, _C_CTYPE_CNTRL, _C_CTYPE_A_THRU_F_N) + (_C_CTYPE_DIGIT_N, _C_CTYPE_LOWER_N, _C_CTYPE_UPPER_N) + (_C_CTYPE_CASES, _C_CTYPE_A_THRU_F, _C_CTYPE_DIGIT, _C_CTYPE_LOWER) + (_C_CTYPE_UPPER, _C_CTYPE_PUNCT_PLAIN): + New private macros. + (_C_CTYPE_CNTRL): In EBCDIC, '\x07' is a control, not '\xff'. + (c_isalnum, c_isalpha, c_isascii, c_isblank, c_iscntrl, c_isdigit) + (c_isgraph, c_islower, c_isprint, c_ispunct, c_isspace, c_isupper) + (c_isxdigit, c_tolower, c_toupper): Now inline functions. + (c_tolower, c_toupper): When converting, return the unsigned char, + as that is what z/OS does. + * lib/c-strcaseeq.h (CASEEQ): Simplify in the light of the removal + of some c-ctype.h macros. + * modules/c-ctype (Depends-on): Add extern-inline; remove verify. + * tests/test-c-ctype.c (test_all): Fix test for c_toupper and + c_tolower promotion to be compatible with z/OS. + 2015-09-24 Pavel Raiskup gitlog-to-changelog: trim only trailing whitespaces diff --git a/NEWS b/NEWS index 55f60fd309..122abf54ba 100644 --- a/NEWS +++ b/NEWS @@ -42,6 +42,11 @@ User visible incompatible changes Date Modules Changes +2015-09-25 c-ctype The following macros were removed: + C_CTYPE_CONSECUTIVE_DIGITS + C_CTYPE_CONSECUTIVE_LOWERCASE + C_CTYPE_CONSECUTIVE_UPPERCASE + 2015-09-22 savewd SAVEWD_CHDIR_READABLE constant removed. 2015-07-24 fprintftime Exported functions' time zone arguments are now of diff --git a/lib/c-ctype.c b/lib/c-ctype.c index a3913a1832..5d9d4d87a6 100644 --- a/lib/c-ctype.c +++ b/lib/c-ctype.c @@ -1,459 +1,3 @@ -/* Character handling in C locale. - - Copyright 2000-2003, 2006, 2009-2015 Free Software Foundation, Inc. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, see . */ - #include - -/* Specification. */ -#define NO_C_CTYPE_MACROS +#define C_CTYPE_INLINE _GL_EXTERN_INLINE #include "c-ctype.h" - -#include -#include "verify.h" - -#ifndef C_CTYPE_ASCII -enum { C_CTYPE_ASCII = false }; -#endif -#ifndef C_CTYPE_CONSECUTIVE_DIGITS -enum { C_CTYPE_CONSECUTIVE_DIGITS = false }; -#endif -#ifndef C_CTYPE_CONSECUTIVE_LOWERCASE -enum { C_CTYPE_CONSECUTIVE_LOWERCASE = false }; -#endif -#ifndef C_CTYPE_CONSECUTIVE_UPPERCASE -enum { C_CTYPE_CONSECUTIVE_UPPERCASE = false }; -#endif - -enum - { - /* True if this appears to be a host using EBCDIC. */ - C_CTYPE_EBCDIC = (' ' == '\x40' && '0' == '\xf0' - && 'A' == '\xc1' && 'J' == '\xd1' && 'S' == '\xe2' - && 'a' == '\x81' && 'j' == '\x91' && 's' == '\xa2') - }; - -/* The implementation currently supports ASCII and EBCDIC. */ -verify (C_CTYPE_ASCII || C_CTYPE_EBCDIC); - -/* Convert an int, which may be promoted from either an unsigned or a - signed char, to the corresponding char. */ - -static char -to_char (int c) -{ - enum { nchars = CHAR_MAX - CHAR_MIN + 1 }; - if (CHAR_MIN < 0 && CHAR_MAX < c && c < nchars) - return c - nchars; - return c; -} - -/* The function isascii is not locale dependent. Its use in EBCDIC is - questionable. */ -bool -c_isascii (int c) -{ - if (C_CTYPE_ASCII) - return 0 <= c && c <= 0x7f; - - /* Use EBCDIC code page 1047's assignments for ASCII control chars; - assume all EBCDIC code pages agree about these assignments. */ - switch (to_char (c)) - { - case '\x00': case '\x01': case '\x02': case '\x03': case '\x05': - case '\x0b': case '\x0c': case '\x0d': case '\x0e': case '\x0f': - case '\x10': case '\x11': case '\x12': case '\x13': case '\x15': - case '\x16': case '\x18': case '\x19': case '\x1c': case '\x1d': - case '\x1e': case '\x1f': case '\x26': case '\x27': case '\x2d': - case '\x2e': case '\x2f': case '\x32': case '\x37': case '\x3c': - case '\x3d': case '\x3f': case '\xff': - case '\xff' < 0 ? 0xff : -1: - - case ' ': case '!': case '"': case '#': case '$': case '%': - case '&': case '\'': case '(': case ')': case '*': case '+': - case ',': case '-': case '.': case '/': - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - case ':': case ';': case '<': case '=': case '>': case '?': - case '@': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case '[': case '\\': case ']': case '^': case '_': case '`': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case '{': case '|': case '}': case '~': - return true; - default: - return false; - } -} - -bool -c_isalnum (int c) -{ - if (C_CTYPE_CONSECUTIVE_DIGITS - && C_CTYPE_CONSECUTIVE_UPPERCASE - && C_CTYPE_CONSECUTIVE_LOWERCASE) - { - if (C_CTYPE_ASCII) - return (('0' <= c && c <= '9') - || ('A' <= (c & ~0x20) && (c & ~0x20) <= 'Z')); - else - return (('0' <= c && c <= '9') - || ('A' <= c && c <= 'Z') - || ('a' <= c && c <= 'z')); - } - - switch (to_char (c)) - { - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - return true; - default: - return false; - } -} - -bool -c_isalpha (int c) -{ - if (C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE) - { - if (C_CTYPE_ASCII) - return 'A' <= (c & ~0x20) && (c & ~0x20) <= 'Z'; - else - return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); - } - - switch (to_char (c)) - { - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - return true; - default: - return false; - } -} - -bool -c_isblank (int c) -{ - return (c == ' ' || c == '\t'); -} - -bool -c_iscntrl (int c) -{ - if (C_CTYPE_ASCII) - return (0 <= c && c < ' ') || c == 0x7f; - - /* Use EBCDIC code page 1047's assignments for ASCII control chars; - assume all EBCDIC code pages agree about these assignments. */ - switch (c) - { - case '\x00': case '\x01': case '\x02': case '\x03': case '\x05': - case '\x0b': case '\x0c': case '\x0d': case '\x0e': case '\x0f': - case '\x10': case '\x11': case '\x12': case '\x13': case '\x15': - case '\x16': case '\x18': case '\x19': case '\x1c': case '\x1d': - case '\x1e': case '\x1f': case '\x26': case '\x27': case '\x2d': - case '\x2e': case '\x2f': case '\x32': case '\x37': case '\x3c': - case '\x3d': case '\x3f': case '\xff': - case '\xff' < 0 ? 0xff : -1: - return true; - default: - return false; - } -} - -bool -c_isdigit (int c) -{ - if (C_CTYPE_ASCII) - return '0' <= c && c <= '9'; - - c = to_char (c); - if (C_CTYPE_CONSECUTIVE_DIGITS) - return '0' <= c && c <= '9'; - - switch (c) - { - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - return true; - default: - return false; - } -} - -bool -c_islower (int c) -{ - if (C_CTYPE_CONSECUTIVE_LOWERCASE) - return 'a' <= c && c <= 'z'; - - switch (to_char (c)) - { - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - return true; - default: - return false; - } -} - -bool -c_isgraph (int c) -{ - if (C_CTYPE_ASCII) - return '!' <= c && c <= '~'; - - switch (to_char (c)) - { - case '!': case '"': case '#': case '$': case '%': case '&': - case '\'': case '(': case ')': case '*': case '+': case ',': - case '-': case '.': case '/': - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - case ':': case ';': case '<': case '=': case '>': case '?': - case '@': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case '[': case '\\': case ']': case '^': case '_': case '`': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case '{': case '|': case '}': case '~': - return true; - default: - return false; - } -} - -bool -c_isprint (int c) -{ - if (C_CTYPE_ASCII) - return ' ' <= c && c <= '~'; - - switch (to_char (c)) - { - case ' ': case '!': case '"': case '#': case '$': case '%': - case '&': case '\'': case '(': case ')': case '*': case '+': - case ',': case '-': case '.': case '/': - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - case ':': case ';': case '<': case '=': case '>': case '?': - case '@': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case '[': case '\\': case ']': case '^': case '_': case '`': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case '{': case '|': case '}': case '~': - return true; - default: - return false; - } -} - -bool -c_ispunct (int c) -{ - if (C_CTYPE_ASCII) - return (('!' <= c && c <= '~') - && !(('0' <= c && c <= '9') - || ('A' <= (c & ~0x20) && (c & ~0x20) <= 'Z'))); - - switch (to_char (c)) - { - case '!': case '"': case '#': case '$': case '%': case '&': - case '\'': case '(': case ')': case '*': case '+': case ',': - case '-': case '.': case '/': - case ':': case ';': case '<': case '=': case '>': case '?': - case '@': - case '[': case '\\': case ']': case '^': case '_': case '`': - case '{': case '|': case '}': case '~': - return true; - default: - return false; - } -} - -bool -c_isspace (int c) -{ - return (c == ' ' || c == '\t' - || c == '\n' || c == '\v' || c == '\f' || c == '\r'); -} - -bool -c_isupper (int c) -{ - if (C_CTYPE_CONSECUTIVE_UPPERCASE) - return 'A' <= c && c <= 'Z'; - - switch (to_char (c)) - { - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - return true; - default: - return false; - } -} - -bool -c_isxdigit (int c) -{ - if (C_CTYPE_CONSECUTIVE_DIGITS - && C_CTYPE_CONSECUTIVE_UPPERCASE - && C_CTYPE_CONSECUTIVE_LOWERCASE) - { - if ('0' <= c && c <= '9') - return true; - if (C_CTYPE_ASCII) - return 'A' <= (c & ~0x20) && (c & ~0x20) <= 'F'; - return (('A' <= c && c <= 'F') - || ('a' <= c && c <= 'f')); - } - - switch (to_char (c)) - { - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - return true; - default: - return false; - } -} - -int -c_tolower (int c) -{ - if (C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE) - return c_isupper (c) ? c - 'A' + 'a' : c; - - switch (to_char (c)) - { - case 'A': return 'a'; - case 'B': return 'b'; - case 'C': return 'c'; - case 'D': return 'd'; - case 'E': return 'e'; - case 'F': return 'f'; - case 'G': return 'g'; - case 'H': return 'h'; - case 'I': return 'i'; - case 'J': return 'j'; - case 'K': return 'k'; - case 'L': return 'l'; - case 'M': return 'm'; - case 'N': return 'n'; - case 'O': return 'o'; - case 'P': return 'p'; - case 'Q': return 'q'; - case 'R': return 'r'; - case 'S': return 's'; - case 'T': return 't'; - case 'U': return 'u'; - case 'V': return 'v'; - case 'W': return 'w'; - case 'X': return 'x'; - case 'Y': return 'y'; - case 'Z': return 'z'; - default: return c; - } -} - -int -c_toupper (int c) -{ - if (C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE) - return c_islower (c) ? c - 'a' + 'A' : c; - - switch (to_char (c)) - { - case 'a': return 'A'; - case 'b': return 'B'; - case 'c': return 'C'; - case 'd': return 'D'; - case 'e': return 'E'; - case 'f': return 'F'; - case 'g': return 'G'; - case 'h': return 'H'; - case 'i': return 'I'; - case 'j': return 'J'; - case 'k': return 'K'; - case 'l': return 'L'; - case 'm': return 'M'; - case 'n': return 'N'; - case 'o': return 'O'; - case 'p': return 'P'; - case 'q': return 'Q'; - case 'r': return 'R'; - case 's': return 'S'; - case 't': return 'T'; - case 'u': return 'U'; - case 'v': return 'V'; - case 'w': return 'W'; - case 'x': return 'X'; - case 'y': return 'Y'; - case 'z': return 'Z'; - default: return c; - } -} diff --git a/lib/c-ctype.h b/lib/c-ctype.h index d6229731b3..1292fc85c6 100644 --- a/lib/c-ctype.h +++ b/lib/c-ctype.h @@ -25,6 +25,13 @@ along with this program; if not, see . */ #include +#ifndef _GL_INLINE_HEADER_BEGIN + #error "Please include config.h first." +#endif +_GL_INLINE_HEADER_BEGIN +#ifndef C_CTYPE_INLINE +# define C_CTYPE_INLINE _GL_INLINE +#endif #ifdef __cplusplus extern "C" { @@ -39,38 +46,6 @@ extern "C" { characters. */ -/* Check whether the ASCII optimizations apply. */ - -/* ANSI C89 (and ISO C99 5.2.1.3 too) already guarantees that - '0', '1', ..., '9' have consecutive integer values. */ -#define C_CTYPE_CONSECUTIVE_DIGITS 1 - -#if ('A' <= 'Z') \ - && ('A' + 1 == 'B') && ('B' + 1 == 'C') && ('C' + 1 == 'D') \ - && ('D' + 1 == 'E') && ('E' + 1 == 'F') && ('F' + 1 == 'G') \ - && ('G' + 1 == 'H') && ('H' + 1 == 'I') && ('I' + 1 == 'J') \ - && ('J' + 1 == 'K') && ('K' + 1 == 'L') && ('L' + 1 == 'M') \ - && ('M' + 1 == 'N') && ('N' + 1 == 'O') && ('O' + 1 == 'P') \ - && ('P' + 1 == 'Q') && ('Q' + 1 == 'R') && ('R' + 1 == 'S') \ - && ('S' + 1 == 'T') && ('T' + 1 == 'U') && ('U' + 1 == 'V') \ - && ('V' + 1 == 'W') && ('W' + 1 == 'X') && ('X' + 1 == 'Y') \ - && ('Y' + 1 == 'Z') -#define C_CTYPE_CONSECUTIVE_UPPERCASE 1 -#endif - -#if ('a' <= 'z') \ - && ('a' + 1 == 'b') && ('b' + 1 == 'c') && ('c' + 1 == 'd') \ - && ('d' + 1 == 'e') && ('e' + 1 == 'f') && ('f' + 1 == 'g') \ - && ('g' + 1 == 'h') && ('h' + 1 == 'i') && ('i' + 1 == 'j') \ - && ('j' + 1 == 'k') && ('k' + 1 == 'l') && ('l' + 1 == 'm') \ - && ('m' + 1 == 'n') && ('n' + 1 == 'o') && ('o' + 1 == 'p') \ - && ('p' + 1 == 'q') && ('q' + 1 == 'r') && ('r' + 1 == 's') \ - && ('s' + 1 == 't') && ('t' + 1 == 'u') && ('u' + 1 == 'v') \ - && ('v' + 1 == 'w') && ('w' + 1 == 'x') && ('x' + 1 == 'y') \ - && ('y' + 1 == 'z') -#define C_CTYPE_CONSECUTIVE_LOWERCASE 1 -#endif - #if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ @@ -96,11 +71,99 @@ extern "C" { && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126) /* The character set is ASCII or one of its variants or extensions, not EBCDIC. Testing the value of '\n' and '\r' is not relevant. */ -#define C_CTYPE_ASCII 1 +# define C_CTYPE_ASCII 1 +#elif ! (' ' == '\x40' && '0' == '\xf0' \ + && 'A' == '\xc1' && 'J' == '\xd1' && 'S' == '\xe2' \ + && 'a' == '\x81' && 'j' == '\x91' && 's' == '\xa2') +# error "Only ASCII and EBCDIC are supported" +#endif + +#define _C_CTYPE_SIGNED_EBCDIC ('A' < 0) + +#if C_CTYPE_ASCII +# define _C_CTYPE_CNTRL \ + case '\x00': case '\x01': case '\x02': case '\x03': \ + case '\x04': case '\x05': case '\x06': case '\x07': \ + case '\x08': case '\x09': case '\x0a': case '\x0b': \ + case '\x0c': case '\x0d': case '\x0e': case '\x0f': \ + case '\x10': case '\x11': case '\x12': case '\x13': \ + case '\x14': case '\x15': case '\x16': case '\x17': \ + case '\x18': case '\x19': case '\x1a': case '\x1b': \ + case '\x1c': case '\x1d': case '\x1e': case '\x1f': \ + case '\x7f' +#else + /* Use EBCDIC code page 1047's assignments for ASCII control chars; + assume all EBCDIC code pages agree about these assignments. */ +# define _C_CTYPE_CNTRL \ + case '\x00': case '\x01': case '\x02': case '\x03': \ + case '\x05': case '\x07': case '\x0b': case '\x0c': \ + case '\x0d': case '\x0e': case '\x0f': case '\x10': \ + case '\x11': case '\x12': case '\x13': case '\x16': \ + case '\x18': case '\x19': case '\x1c': case '\x1d': \ + case '\x1e': case '\x1f': case '\x25': case '\x26': \ + case '\x27': case '\x2d': case '\x2e': case '\x2f': \ + case '\x32': case '\x37': case '\x3c': case '\x3d': \ + case '\x3f' #endif +/* Cases for hex letter digits, digits, lower, and upper, offset by N. */ + +#define _C_CTYPE_A_THRU_F_N(n) \ + case 'a' + (n): case 'b' + (n): case 'c' + (n): case 'd' + (n): \ + case 'e' + (n): case 'f' + (n): \ + case 'A' + (n): case 'B' + (n): case 'C' + (n): case 'D' + (n): \ + case 'E' + (n): case 'F' + (n) +#define _C_CTYPE_DIGIT_N(n) \ + case '0' + (n): case '1' + (n): case '2' + (n): case '3' + (n): \ + case '4' + (n): case '5' + (n): case '6' + (n): case '7' + (n): \ + case '8' + (n): case '9' + (n) +#define _C_CTYPE_LOWER_N(n) \ + case 'a' + (n): case 'b' + (n): case 'c' + (n): case 'd' + (n): \ + case 'e' + (n): case 'f' + (n): case 'g' + (n): case 'h' + (n): \ + case 'i' + (n): case 'j' + (n): case 'k' + (n): case 'l' + (n): \ + case 'm' + (n): case 'n' + (n): case 'o' + (n): case 'p' + (n): \ + case 'q' + (n): case 'r' + (n): case 's' + (n): case 't' + (n): \ + case 'u' + (n): case 'v' + (n): case 'w' + (n): case 'x' + (n): \ + case 'y' + (n): case 'z' + (n) +#define _C_CTYPE_UPPER_N(n) \ + case 'A' + (n): case 'B' + (n): case 'C' + (n): case 'D' + (n): \ + case 'E' + (n): case 'F' + (n): case 'G' + (n): case 'H' + (n): \ + case 'I' + (n): case 'J' + (n): case 'K' + (n): case 'L' + (n): \ + case 'M' + (n): case 'N' + (n): case 'O' + (n): case 'P' + (n): \ + case 'Q' + (n): case 'R' + (n): case 'S' + (n): case 'T' + (n): \ + case 'U' + (n): case 'V' + (n): case 'W' + (n): case 'X' + (n): \ + case 'Y' + (n): case 'Z' + (n) + +/* Given MACRO_N, expand to all the cases for the corresponding class. */ +#if _C_CTYPE_SIGNED_EBCDIC +# define _C_CTYPE_CASES(macro_n) macro_n (0): macro_n (256) +#else +# define _C_CTYPE_CASES(macro_n) macro_n (0) +#endif -/* Function declarations. */ +/* Cases for hex letter digits, digits, lower, and upper, with another + case for unsigned char if the original char is negative. */ + +#define _C_CTYPE_A_THRU_F _C_CTYPE_CASES (_C_CTYPE_A_THRU_F_N) +#define _C_CTYPE_DIGIT _C_CTYPE_CASES (_C_CTYPE_DIGIT_N) +#define _C_CTYPE_LOWER _C_CTYPE_CASES (_C_CTYPE_LOWER_N) +#define _C_CTYPE_UPPER _C_CTYPE_CASES (_C_CTYPE_UPPER_N) + +/* The punct class differs because some punctuation characters may be + negative while others are nonnegative. Instead of attempting to + define _C_CTYPE_PUNCT, define just the plain chars here, and do any + cases-plus-256 by hand after using this macro. */ +#define _C_CTYPE_PUNCT_PLAIN \ + case '!': case '"': case '#': case '$': \ + case '%': case '&': case '\'': case '(': \ + case ')': case '*': case '+': case ',': \ + case '-': case '.': case '/': case ':': \ + case ';': case '<': case '=': case '>': \ + case '?': case '@': case '[': case '\\': \ + case ']': case '^': case '_': case '`': \ + case '{': case '|': case '}': case '~' + +/* Function definitions. */ /* Unlike the functions in , which require an argument in the range of the 'unsigned char' type, the functions here operate on values that are @@ -117,179 +180,608 @@ extern "C" { if (c_isalpha (*s)) ... */ -extern bool c_isascii (int c) _GL_ATTRIBUTE_CONST; /* not locale dependent */ +C_CTYPE_INLINE bool +c_isalnum (int c) +{ + switch (c) + { + _C_CTYPE_DIGIT: + _C_CTYPE_LOWER: + _C_CTYPE_UPPER: + return true; + + default: + return false; + } +} -extern bool c_isalnum (int c) _GL_ATTRIBUTE_CONST; -extern bool c_isalpha (int c) _GL_ATTRIBUTE_CONST; -extern bool c_isblank (int c) _GL_ATTRIBUTE_CONST; -extern bool c_iscntrl (int c) _GL_ATTRIBUTE_CONST; -extern bool c_isdigit (int c) _GL_ATTRIBUTE_CONST; -extern bool c_islower (int c) _GL_ATTRIBUTE_CONST; -extern bool c_isgraph (int c) _GL_ATTRIBUTE_CONST; -extern bool c_isprint (int c) _GL_ATTRIBUTE_CONST; -extern bool c_ispunct (int c) _GL_ATTRIBUTE_CONST; -extern bool c_isspace (int c) _GL_ATTRIBUTE_CONST; -extern bool c_isupper (int c) _GL_ATTRIBUTE_CONST; -extern bool c_isxdigit (int c) _GL_ATTRIBUTE_CONST; +C_CTYPE_INLINE bool +c_isalpha (int c) +{ + switch (c) + { + _C_CTYPE_LOWER: + _C_CTYPE_UPPER: + return true; + + default: + return false; + } +} -extern int c_tolower (int c) _GL_ATTRIBUTE_CONST; -extern int c_toupper (int c) _GL_ATTRIBUTE_CONST; +/* The function isascii is not locale dependent. + Its use in EBCDIC is questionable. */ +C_CTYPE_INLINE bool +c_isascii (int c) +{ + switch (c) + { + case ' ': + _C_CTYPE_CNTRL: + _C_CTYPE_DIGIT: + _C_CTYPE_LOWER: + _C_CTYPE_UPPER: + + _C_CTYPE_PUNCT_PLAIN: +#if '!' < 0 + case '!' + 256: +#endif +#if '"' < 0 + case '"' + 256: +#endif +#if '#' < 0 + case '#' + 256: +#endif +#if '$' < 0 + case '$' + 256: +#endif +#if '%' < 0 + case '%' + 256: +#endif +#if '&' < 0 + case '&' + 256: +#endif +#if '\'' < 0 + case '\'' + 256: +#endif +#if '(' < 0 + case '(' + 256: +#endif +#if ')' < 0 + case ')' + 256: +#endif +#if '*' < 0 + case '*' + 256: +#endif +#if '+' < 0 + case '+' + 256: +#endif +#if ',' < 0 + case ',' + 256: +#endif +#if '-' < 0 + case '-' + 256: +#endif +#if '.' < 0 + case '.' + 256: +#endif +#if '/' < 0 + case '/' + 256: +#endif +#if ':' < 0 + case ':' + 256: +#endif +#if ';' < 0 + case ';' + 256: +#endif +#if '<' < 0 + case '<' + 256: +#endif +#if '=' < 0 + case '=' + 256: +#endif +#if '>' < 0 + case '>' + 256: +#endif +#if '?' < 0 + case '?' + 256: +#endif +#if '@' < 0 + case '@' + 256: +#endif +#if '[' < 0 + case '[' + 256: +#endif +#if '\\' < 0 + case '\\' + 256: +#endif +#if ']' < 0 + case ']' + 256: +#endif +#if '^' < 0 + case '^' + 256: +#endif +#if '_' < 0 + case '_' + 256: +#endif +#if '`' < 0 + case '`' + 256: +#endif +#if '{' < 0 + case '{' + 256: +#endif +#if '|' < 0 + case '|' + 256: +#endif +#if '}' < 0 + case '}' + 256: +#endif +#if '~' < 0 + case '~' + 256: +#endif + return true; + default: + return false; + } +} -#if (defined __GNUC__ && !defined __STRICT_ANSI__ && defined __OPTIMIZE__ \ - && !defined __OPTIMIZE_SIZE__ && !defined NO_C_CTYPE_MACROS) +C_CTYPE_INLINE bool +c_isblank (int c) +{ + return c == ' ' || c == '\t'; +} -/* ASCII optimizations. */ +C_CTYPE_INLINE bool +c_iscntrl (int c) +{ + switch (c) + { + _C_CTYPE_CNTRL: + return true; + default: + return false; + } +} -#undef c_isascii -#define c_isascii(c) \ - ({ int __c = (c); \ - (__c >= 0x00 && __c <= 0x7f); \ - }) +C_CTYPE_INLINE bool +c_isdigit (int c) +{ + switch (c) + { + _C_CTYPE_DIGIT: + return true; + default: + return false; + } +} -#if C_CTYPE_CONSECUTIVE_DIGITS \ - && C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE -#if C_CTYPE_ASCII -#undef c_isalnum -#define c_isalnum(c) \ - ({ int __c = (c); \ - ((__c >= '0' && __c <= '9') \ - || ((__c & ~0x20) >= 'A' && (__c & ~0x20) <= 'Z')); \ - }) -#else -#undef c_isalnum -#define c_isalnum(c) \ - ({ int __c = (c); \ - ((__c >= '0' && __c <= '9') \ - || (__c >= 'A' && __c <= 'Z') \ - || (__c >= 'a' && __c <= 'z')); \ - }) +C_CTYPE_INLINE bool +c_isgraph (int c) +{ + switch (c) + { + _C_CTYPE_DIGIT: + _C_CTYPE_LOWER: + _C_CTYPE_UPPER: + + _C_CTYPE_PUNCT_PLAIN: +#if '!' < 0 + case '!' + 256: #endif +#if '"' < 0 + case '"' + 256: #endif - -#if C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE -#if C_CTYPE_ASCII -#undef c_isalpha -#define c_isalpha(c) \ - ({ int __c = (c); \ - ((__c & ~0x20) >= 'A' && (__c & ~0x20) <= 'Z'); \ - }) -#else -#undef c_isalpha -#define c_isalpha(c) \ - ({ int __c = (c); \ - ((__c >= 'A' && __c <= 'Z') || (__c >= 'a' && __c <= 'z')); \ - }) +#if '#' < 0 + case '#' + 256: +#endif +#if '$' < 0 + case '$' + 256: +#endif +#if '%' < 0 + case '%' + 256: +#endif +#if '&' < 0 + case '&' + 256: +#endif +#if '\'' < 0 + case '\'' + 256: +#endif +#if '(' < 0 + case '(' + 256: +#endif +#if ')' < 0 + case ')' + 256: +#endif +#if '*' < 0 + case '*' + 256: +#endif +#if '+' < 0 + case '+' + 256: +#endif +#if ',' < 0 + case ',' + 256: +#endif +#if '-' < 0 + case '-' + 256: +#endif +#if '.' < 0 + case '.' + 256: +#endif +#if '/' < 0 + case '/' + 256: +#endif +#if ':' < 0 + case ':' + 256: +#endif +#if ';' < 0 + case ';' + 256: +#endif +#if '<' < 0 + case '<' + 256: +#endif +#if '=' < 0 + case '=' + 256: +#endif +#if '>' < 0 + case '>' + 256: +#endif +#if '?' < 0 + case '?' + 256: +#endif +#if '@' < 0 + case '@' + 256: +#endif +#if '[' < 0 + case '[' + 256: +#endif +#if '\\' < 0 + case '\\' + 256: +#endif +#if ']' < 0 + case ']' + 256: +#endif +#if '^' < 0 + case '^' + 256: +#endif +#if '_' < 0 + case '_' + 256: +#endif +#if '`' < 0 + case '`' + 256: +#endif +#if '{' < 0 + case '{' + 256: +#endif +#if '|' < 0 + case '|' + 256: +#endif +#if '}' < 0 + case '}' + 256: #endif +#if '~' < 0 + case '~' + 256: #endif + return true; -#undef c_isblank -#define c_isblank(c) \ - ({ int __c = (c); \ - (__c == ' ' || __c == '\t'); \ - }) + default: + return false; + } +} -#if C_CTYPE_ASCII -#undef c_iscntrl -#define c_iscntrl(c) \ - ({ int __c = (c); \ - ((__c & ~0x1f) == 0 || __c == 0x7f); \ - }) -#endif +C_CTYPE_INLINE bool +c_islower (int c) +{ + switch (c) + { + _C_CTYPE_LOWER: + return true; + default: + return false; + } +} -#if C_CTYPE_CONSECUTIVE_DIGITS -#undef c_isdigit -#define c_isdigit(c) \ - ({ int __c = (c); \ - (__c >= '0' && __c <= '9'); \ - }) +C_CTYPE_INLINE bool +c_isprint (int c) +{ + switch (c) + { + case ' ': + _C_CTYPE_DIGIT: + _C_CTYPE_LOWER: + _C_CTYPE_UPPER: + + _C_CTYPE_PUNCT_PLAIN: +#if '!' < 0 + case '!' + 256: #endif - -#if C_CTYPE_CONSECUTIVE_LOWERCASE -#undef c_islower -#define c_islower(c) \ - ({ int __c = (c); \ - (__c >= 'a' && __c <= 'z'); \ - }) +#if '"' < 0 + case '"' + 256: #endif - -#if C_CTYPE_ASCII -#undef c_isgraph -#define c_isgraph(c) \ - ({ int __c = (c); \ - (__c >= '!' && __c <= '~'); \ - }) +#if '#' < 0 + case '#' + 256: #endif - -#if C_CTYPE_ASCII -#undef c_isprint -#define c_isprint(c) \ - ({ int __c = (c); \ - (__c >= ' ' && __c <= '~'); \ - }) +#if '$' < 0 + case '$' + 256: +#endif +#if '%' < 0 + case '%' + 256: +#endif +#if '&' < 0 + case '&' + 256: +#endif +#if '\'' < 0 + case '\'' + 256: +#endif +#if '(' < 0 + case '(' + 256: +#endif +#if ')' < 0 + case ')' + 256: +#endif +#if '*' < 0 + case '*' + 256: +#endif +#if '+' < 0 + case '+' + 256: +#endif +#if ',' < 0 + case ',' + 256: +#endif +#if '-' < 0 + case '-' + 256: +#endif +#if '.' < 0 + case '.' + 256: +#endif +#if '/' < 0 + case '/' + 256: +#endif +#if ':' < 0 + case ':' + 256: +#endif +#if ';' < 0 + case ';' + 256: #endif +#if '<' < 0 + case '<' + 256: +#endif +#if '=' < 0 + case '=' + 256: +#endif +#if '>' < 0 + case '>' + 256: +#endif +#if '?' < 0 + case '?' + 256: +#endif +#if '@' < 0 + case '@' + 256: +#endif +#if '[' < 0 + case '[' + 256: +#endif +#if '\\' < 0 + case '\\' + 256: +#endif +#if ']' < 0 + case ']' + 256: +#endif +#if '^' < 0 + case '^' + 256: +#endif +#if '_' < 0 + case '_' + 256: +#endif +#if '`' < 0 + case '`' + 256: +#endif +#if '{' < 0 + case '{' + 256: +#endif +#if '|' < 0 + case '|' + 256: +#endif +#if '}' < 0 + case '}' + 256: +#endif +#if '~' < 0 + case '~' + 256: +#endif + return true; -#if C_CTYPE_ASCII -#undef c_ispunct -#define c_ispunct(c) \ - ({ int _c = (c); \ - (c_isgraph (_c) && ! c_isalnum (_c)); \ - }) -#endif - -#undef c_isspace -#define c_isspace(c) \ - ({ int __c = (c); \ - (__c == ' ' || __c == '\t' \ - || __c == '\n' || __c == '\v' || __c == '\f' || __c == '\r'); \ - }) - -#if C_CTYPE_CONSECUTIVE_UPPERCASE -#undef c_isupper -#define c_isupper(c) \ - ({ int __c = (c); \ - (__c >= 'A' && __c <= 'Z'); \ - }) -#endif - -#if C_CTYPE_CONSECUTIVE_DIGITS \ - && C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE -#if C_CTYPE_ASCII -#undef c_isxdigit -#define c_isxdigit(c) \ - ({ int __c = (c); \ - ((__c >= '0' && __c <= '9') \ - || ((__c & ~0x20) >= 'A' && (__c & ~0x20) <= 'F')); \ - }) -#else -#undef c_isxdigit -#define c_isxdigit(c) \ - ({ int __c = (c); \ - ((__c >= '0' && __c <= '9') \ - || (__c >= 'A' && __c <= 'F') \ - || (__c >= 'a' && __c <= 'f')); \ - }) + default: + return false; + } +} + +C_CTYPE_INLINE bool +c_ispunct (int c) +{ + switch (c) + { + _C_CTYPE_PUNCT_PLAIN: +#if '!' < 0 + case '!' + 256: +#endif +#if '"' < 0 + case '"' + 256: #endif +#if '#' < 0 + case '#' + 256: #endif +#if '$' < 0 + case '$' + 256: +#endif +#if '%' < 0 + case '%' + 256: +#endif +#if '&' < 0 + case '&' + 256: +#endif +#if '\'' < 0 + case '\'' + 256: +#endif +#if '(' < 0 + case '(' + 256: +#endif +#if ')' < 0 + case ')' + 256: +#endif +#if '*' < 0 + case '*' + 256: +#endif +#if '+' < 0 + case '+' + 256: +#endif +#if ',' < 0 + case ',' + 256: +#endif +#if '-' < 0 + case '-' + 256: +#endif +#if '.' < 0 + case '.' + 256: +#endif +#if '/' < 0 + case '/' + 256: +#endif +#if ':' < 0 + case ':' + 256: +#endif +#if ';' < 0 + case ';' + 256: +#endif +#if '<' < 0 + case '<' + 256: +#endif +#if '=' < 0 + case '=' + 256: +#endif +#if '>' < 0 + case '>' + 256: +#endif +#if '?' < 0 + case '?' + 256: +#endif +#if '@' < 0 + case '@' + 256: +#endif +#if '[' < 0 + case '[' + 256: +#endif +#if '\\' < 0 + case '\\' + 256: +#endif +#if ']' < 0 + case ']' + 256: +#endif +#if '^' < 0 + case '^' + 256: +#endif +#if '_' < 0 + case '_' + 256: +#endif +#if '`' < 0 + case '`' + 256: +#endif +#if '{' < 0 + case '{' + 256: +#endif +#if '|' < 0 + case '|' + 256: +#endif +#if '}' < 0 + case '}' + 256: +#endif +#if '~' < 0 + case '~' + 256: +#endif + return true; -#if C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE -#undef c_tolower -#define c_tolower(c) \ - ({ int __c = (c); \ - (__c >= 'A' && __c <= 'Z' ? __c - 'A' + 'a' : __c); \ - }) -#undef c_toupper -#define c_toupper(c) \ - ({ int __c = (c); \ - (__c >= 'a' && __c <= 'z' ? __c - 'a' + 'A' : __c); \ - }) + default: + return false; + } +} + +C_CTYPE_INLINE bool +c_isspace (int c) +{ + switch (c) + { + case ' ': case '\t': case '\n': case '\v': case '\f': case '\r': + return true; + default: + return false; + } +} + +C_CTYPE_INLINE bool +c_isupper (int c) +{ + switch (c) + { + _C_CTYPE_UPPER: + return true; + default: + return false; + } +} + +C_CTYPE_INLINE bool +c_isxdigit (int c) +{ + switch (c) + { + _C_CTYPE_DIGIT: + _C_CTYPE_A_THRU_F: + return true; + + default: + return false; + } +} + +C_CTYPE_INLINE int +c_tolower (int c) +{ + switch (c) + { + _C_CTYPE_UPPER_N (0): +#if _C_CTYPE_SIGNED_EBCDIC + c += 256; + /* Fall through. */ + _C_CTYPE_UPPER_N (256): #endif + return c - 'A' + 'a'; -#endif /* optimizing for speed */ + default: + return c; + } +} +C_CTYPE_INLINE int +c_toupper (int c) +{ + switch (c) + { + _C_CTYPE_LOWER_N (0): +#if _C_CTYPE_SIGNED_EBCDIC + c += 256; + /* Fall through. */ + _C_CTYPE_LOWER_N (256): +#endif + return c - 'a' + 'A'; + + default: + return c; + } +} #ifdef __cplusplus } #endif +_GL_INLINE_HEADER_END + #endif /* C_CTYPE_H */ diff --git a/lib/c-strcaseeq.h b/lib/c-strcaseeq.h index 896dbccca9..ce4b82dd1c 100644 --- a/lib/c-strcaseeq.h +++ b/lib/c-strcaseeq.h @@ -33,9 +33,6 @@ # if C_CTYPE_ASCII # define CASEEQ(other,upper) \ (c_isupper (upper) ? ((other) & ~0x20) == (upper) : (other) == (upper)) -# elif C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE -# define CASEEQ(other,upper) \ - (c_isupper (upper) ? (other) == (upper) || (other) == (upper) - 'A' + 'a' : (other) == (upper)) # else # define CASEEQ(other,upper) \ (c_toupper (other) == (upper)) diff --git a/modules/c-ctype b/modules/c-ctype index b172d139bb..106050e3b9 100644 --- a/modules/c-ctype +++ b/modules/c-ctype @@ -6,8 +6,8 @@ lib/c-ctype.h lib/c-ctype.c Depends-on: +extern-inline stdbool -verify configure.ac: diff --git a/tests/test-c-ctype.c b/tests/test-c-ctype.c index 481cbbb530..d25dc0369e 100644 --- a/tests/test-c-ctype.c +++ b/tests/test-c-ctype.c @@ -204,218 +204,64 @@ test_all (void) switch (to_char (c)) { - case 'A': - ASSERT (c_tolower (c) == 'a'); - ASSERT (c_toupper (c) == c); - break; - case 'B': - ASSERT (c_tolower (c) == 'b'); - ASSERT (c_toupper (c) == c); - break; - case 'C': - ASSERT (c_tolower (c) == 'c'); - ASSERT (c_toupper (c) == c); - break; - case 'D': - ASSERT (c_tolower (c) == 'd'); - ASSERT (c_toupper (c) == c); - break; - case 'E': - ASSERT (c_tolower (c) == 'e'); - ASSERT (c_toupper (c) == c); - break; - case 'F': - ASSERT (c_tolower (c) == 'f'); - ASSERT (c_toupper (c) == c); - break; - case 'G': - ASSERT (c_tolower (c) == 'g'); - ASSERT (c_toupper (c) == c); - break; - case 'H': - ASSERT (c_tolower (c) == 'h'); - ASSERT (c_toupper (c) == c); - break; - case 'I': - ASSERT (c_tolower (c) == 'i'); - ASSERT (c_toupper (c) == c); - break; - case 'J': - ASSERT (c_tolower (c) == 'j'); - ASSERT (c_toupper (c) == c); - break; - case 'K': - ASSERT (c_tolower (c) == 'k'); - ASSERT (c_toupper (c) == c); - break; - case 'L': - ASSERT (c_tolower (c) == 'l'); - ASSERT (c_toupper (c) == c); - break; - case 'M': - ASSERT (c_tolower (c) == 'm'); - ASSERT (c_toupper (c) == c); - break; - case 'N': - ASSERT (c_tolower (c) == 'n'); - ASSERT (c_toupper (c) == c); - break; - case 'O': - ASSERT (c_tolower (c) == 'o'); - ASSERT (c_toupper (c) == c); - break; - case 'P': - ASSERT (c_tolower (c) == 'p'); - ASSERT (c_toupper (c) == c); - break; - case 'Q': - ASSERT (c_tolower (c) == 'q'); - ASSERT (c_toupper (c) == c); - break; - case 'R': - ASSERT (c_tolower (c) == 'r'); - ASSERT (c_toupper (c) == c); - break; - case 'S': - ASSERT (c_tolower (c) == 's'); - ASSERT (c_toupper (c) == c); - break; - case 'T': - ASSERT (c_tolower (c) == 't'); - ASSERT (c_toupper (c) == c); - break; - case 'U': - ASSERT (c_tolower (c) == 'u'); - ASSERT (c_toupper (c) == c); - break; - case 'V': - ASSERT (c_tolower (c) == 'v'); - ASSERT (c_toupper (c) == c); - break; - case 'W': - ASSERT (c_tolower (c) == 'w'); - ASSERT (c_toupper (c) == c); - break; - case 'X': - ASSERT (c_tolower (c) == 'x'); - ASSERT (c_toupper (c) == c); - break; - case 'Y': - ASSERT (c_tolower (c) == 'y'); - ASSERT (c_toupper (c) == c); - break; - case 'Z': - ASSERT (c_tolower (c) == 'z'); - ASSERT (c_toupper (c) == c); - break; - case 'a': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'A'); - break; - case 'b': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'B'); - break; - case 'c': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'C'); - break; - case 'd': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'D'); - break; - case 'e': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'E'); - break; - case 'f': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'F'); - break; - case 'g': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'G'); - break; - case 'h': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'H'); - break; - case 'i': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'I'); - break; - case 'j': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'J'); - break; - case 'k': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'K'); - break; - case 'l': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'L'); - break; - case 'm': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'M'); - break; - case 'n': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'N'); - break; - case 'o': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'O'); - break; - case 'p': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'P'); - break; - case 'q': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'Q'); - break; - case 'r': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'R'); - break; - case 's': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'S'); - break; - case 't': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'T'); - break; - case 'u': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'U'); - break; - case 'v': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'V'); - break; - case 'w': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'W'); - break; - case 'x': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'X'); - break; - case 'y': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'Y'); - break; - case 'z': - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == 'Z'); - break; - default: - ASSERT (c_tolower (c) == c); - ASSERT (c_toupper (c) == c); - break; + case 'A': ASSERT (to_char (c_tolower (c)) == 'a'); break; + case 'B': ASSERT (to_char (c_tolower (c)) == 'b'); break; + case 'C': ASSERT (to_char (c_tolower (c)) == 'c'); break; + case 'D': ASSERT (to_char (c_tolower (c)) == 'd'); break; + case 'E': ASSERT (to_char (c_tolower (c)) == 'e'); break; + case 'F': ASSERT (to_char (c_tolower (c)) == 'f'); break; + case 'G': ASSERT (to_char (c_tolower (c)) == 'g'); break; + case 'H': ASSERT (to_char (c_tolower (c)) == 'h'); break; + case 'I': ASSERT (to_char (c_tolower (c)) == 'i'); break; + case 'J': ASSERT (to_char (c_tolower (c)) == 'j'); break; + case 'K': ASSERT (to_char (c_tolower (c)) == 'k'); break; + case 'L': ASSERT (to_char (c_tolower (c)) == 'l'); break; + case 'M': ASSERT (to_char (c_tolower (c)) == 'm'); break; + case 'N': ASSERT (to_char (c_tolower (c)) == 'n'); break; + case 'O': ASSERT (to_char (c_tolower (c)) == 'o'); break; + case 'P': ASSERT (to_char (c_tolower (c)) == 'p'); break; + case 'Q': ASSERT (to_char (c_tolower (c)) == 'q'); break; + case 'R': ASSERT (to_char (c_tolower (c)) == 'r'); break; + case 'S': ASSERT (to_char (c_tolower (c)) == 's'); break; + case 'T': ASSERT (to_char (c_tolower (c)) == 't'); break; + case 'U': ASSERT (to_char (c_tolower (c)) == 'u'); break; + case 'V': ASSERT (to_char (c_tolower (c)) == 'v'); break; + case 'W': ASSERT (to_char (c_tolower (c)) == 'w'); break; + case 'X': ASSERT (to_char (c_tolower (c)) == 'x'); break; + case 'Y': ASSERT (to_char (c_tolower (c)) == 'y'); break; + case 'Z': ASSERT (to_char (c_tolower (c)) == 'z'); break; + default: ASSERT (c_tolower (c) == c); break; + } + + switch (to_char (c)) + { + case 'a': ASSERT (to_char (c_toupper (c)) == 'A'); break; + case 'b': ASSERT (to_char (c_toupper (c)) == 'B'); break; + case 'c': ASSERT (to_char (c_toupper (c)) == 'C'); break; + case 'd': ASSERT (to_char (c_toupper (c)) == 'D'); break; + case 'e': ASSERT (to_char (c_toupper (c)) == 'E'); break; + case 'f': ASSERT (to_char (c_toupper (c)) == 'F'); break; + case 'g': ASSERT (to_char (c_toupper (c)) == 'G'); break; + case 'h': ASSERT (to_char (c_toupper (c)) == 'H'); break; + case 'i': ASSERT (to_char (c_toupper (c)) == 'I'); break; + case 'j': ASSERT (to_char (c_toupper (c)) == 'J'); break; + case 'k': ASSERT (to_char (c_toupper (c)) == 'K'); break; + case 'l': ASSERT (to_char (c_toupper (c)) == 'L'); break; + case 'm': ASSERT (to_char (c_toupper (c)) == 'M'); break; + case 'n': ASSERT (to_char (c_toupper (c)) == 'N'); break; + case 'o': ASSERT (to_char (c_toupper (c)) == 'O'); break; + case 'p': ASSERT (to_char (c_toupper (c)) == 'P'); break; + case 'q': ASSERT (to_char (c_toupper (c)) == 'Q'); break; + case 'r': ASSERT (to_char (c_toupper (c)) == 'R'); break; + case 's': ASSERT (to_char (c_toupper (c)) == 'S'); break; + case 't': ASSERT (to_char (c_toupper (c)) == 'T'); break; + case 'u': ASSERT (to_char (c_toupper (c)) == 'U'); break; + case 'v': ASSERT (to_char (c_toupper (c)) == 'V'); break; + case 'w': ASSERT (to_char (c_toupper (c)) == 'W'); break; + case 'x': ASSERT (to_char (c_toupper (c)) == 'X'); break; + case 'y': ASSERT (to_char (c_toupper (c)) == 'Y'); break; + case 'z': ASSERT (to_char (c_toupper (c)) == 'Z'); break; + default: ASSERT (c_toupper (c) == c); break; } }