1 /* Multibyte character data type.
2 Copyright (C) 2001, 2005-2007, 2009-2025 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>. */
19 /* A multibyte character is a short subsequence of a char* string,
20 representing a single 32-bit wide character.
22 We use multibyte characters instead of 32-bit wide characters because
23 of the following goals:
24 1) correct multibyte handling, i.e. operate according to the LC_CTYPE
26 2) ease of maintenance, i.e. the maintainer needs not know all details
27 of the ISO C 99 standard,
28 3) don't fail grossly if the input is not in the encoding set by the
29 locale, because often different encodings are in use in the same
30 countries (ISO-8859-1/UTF-8, EUC-JP/Shift_JIS, ...),
31 4) fast in the case of ASCII characters.
33 Multibyte characters are only accessed through the mb* macros.
36 return a pointer to the beginning of the multibyte sequence.
39 returns the number of bytes occupied by the multibyte sequence.
43 returns true if mbc is the standard ASCII character sc.
46 returns true if mbc is the nul character.
49 returns a positive, zero, or negative value depending on whether mbc1
50 sorts after, same or before mbc2.
52 mb_casecmp (mbc1, mbc2)
53 returns a positive, zero, or negative value depending on whether mbc1
54 sorts after, same or before mbc2, modulo upper/lowercase conversion.
57 returns true if mbc1 and mbc2 are equal.
59 mb_caseequal (mbc1, mbc2)
60 returns true if mbc1 and mbc2 are equal modulo upper/lowercase conversion.
63 returns true if mbc is alphanumeric.
66 returns true if mbc is alphabetic.
69 returns true if mbc is plain ASCII.
72 returns true if mbc is a blank.
75 returns true if mbc is a control character.
78 returns true if mbc is a decimal digit.
81 returns true if mbc is a graphic character.
84 returns true if mbc is lowercase.
87 returns true if mbc is a printable character.
90 returns true if mbc is a punctuation character.
93 returns true if mbc is a space character.
96 returns true if mbc is uppercase.
99 returns true if mbc is a hexadecimal digit.
102 returns the number of columns on the output device occupied by mbc.
105 mb_putc (mbc, stream)
106 outputs mbc on stream, a byte oriented FILE stream opened for output.
108 mb_setascii (&mbc, sc)
109 assigns the standard ASCII character sc to mbc.
110 (Only available if the 'mbfile' module is in use.)
112 mb_copy (&destmbc, &srcmbc)
113 copies srcmbc to destmbc.
115 Here are the function prototypes of the macros.
117 extern const char * mb_ptr (const mbchar_t mbc);
118 extern size_t mb_len (const mbchar_t mbc);
119 extern bool mb_iseq (const mbchar_t mbc, char sc);
120 extern bool mb_isnul (const mbchar_t mbc);
121 extern int mb_cmp (const mbchar_t mbc1, const mbchar_t mbc2);
122 extern int mb_casecmp (const mbchar_t mbc1, const mbchar_t mbc2);
123 extern bool mb_equal (const mbchar_t mbc1, const mbchar_t mbc2);
124 extern bool mb_caseequal (const mbchar_t mbc1, const mbchar_t mbc2);
125 extern bool mb_isalnum (const mbchar_t mbc);
126 extern bool mb_isalpha (const mbchar_t mbc);
127 extern bool mb_isascii (const mbchar_t mbc);
128 extern bool mb_isblank (const mbchar_t mbc);
129 extern bool mb_iscntrl (const mbchar_t mbc);
130 extern bool mb_isdigit (const mbchar_t mbc);
131 extern bool mb_isgraph (const mbchar_t mbc);
132 extern bool mb_islower (const mbchar_t mbc);
133 extern bool mb_isprint (const mbchar_t mbc);
134 extern bool mb_ispunct (const mbchar_t mbc);
135 extern bool mb_isspace (const mbchar_t mbc);
136 extern bool mb_isupper (const mbchar_t mbc);
137 extern bool mb_isxdigit (const mbchar_t mbc);
138 extern int mb_width (const mbchar_t mbc);
139 extern void mb_putc (const mbchar_t mbc, FILE *stream);
140 extern void mb_setascii (mbchar_t *new, char sc);
141 extern void mb_copy (mbchar_t *new, const mbchar_t *old);
147 /* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */
148 #if !_GL_CONFIG_H_INCLUDED
149 #error "Please include config.h first."
155 _GL_INLINE_HEADER_BEGIN
156 #ifndef MBCHAR_INLINE
157 # define MBCHAR_INLINE _GL_INLINE
165 /* The longest multibyte characters, nowadays, are 4 bytes long.
166 Regardless of the values of MB_CUR_MAX and MB_LEN_MAX. */
167 #define MBCHAR_BUF_SIZE 4
171 const char *ptr
; /* pointer to current character */
172 size_t bytes
; /* number of bytes of current character, > 0 */
173 bool wc_valid
; /* true if wc is a valid 32-bit wide character */
174 char32_t wc
; /* if wc_valid: the current character */
175 #if defined GNULIB_MBFILE
176 char buf
[MBCHAR_BUF_SIZE
]; /* room for the bytes, used for file input only */
180 /* EOF (not a real character) is represented with bytes = 0 and
183 typedef struct mbchar mbchar_t
;
185 /* Access the current character. */
186 #define mb_ptr(mbc) ((mbc).ptr)
187 #define mb_len(mbc) ((mbc).bytes)
189 /* Comparison of characters. */
190 #define mb_iseq(mbc, sc) ((mbc).wc_valid && (mbc).wc == (sc))
191 #define mb_isnul(mbc) ((mbc).wc_valid && (mbc).wc == 0)
192 #define mb_cmp(mbc1, mbc2) \
195 ? _GL_CMP ((mbc1).wc, (mbc2).wc) \
199 : (mbc1).bytes == (mbc2).bytes \
200 ? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
201 : (mbc1).bytes < (mbc2).bytes \
202 ? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
203 : (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
204 #define mb_casecmp(mbc1, mbc2) \
207 ? _GL_CMP (c32tolower ((mbc1).wc), c32tolower ((mbc2).wc)) \
211 : (mbc1).bytes == (mbc2).bytes \
212 ? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
213 : (mbc1).bytes < (mbc2).bytes \
214 ? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
215 : (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
216 #define mb_equal(mbc1, mbc2) \
217 ((mbc1).wc_valid && (mbc2).wc_valid \
218 ? (mbc1).wc == (mbc2).wc \
219 : (mbc1).bytes == (mbc2).bytes \
220 && memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
221 #define mb_caseequal(mbc1, mbc2) \
222 ((mbc1).wc_valid && (mbc2).wc_valid \
223 ? c32tolower ((mbc1).wc) == c32tolower ((mbc2).wc) \
224 : (mbc1).bytes == (mbc2).bytes \
225 && memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
227 /* <ctype.h>, <wctype.h> classification. */
228 #define mb_isascii(mbc) \
229 ((mbc).wc_valid && (mbc).wc >= 0 && (mbc).wc <= 127)
230 #define mb_isalnum(mbc) ((mbc).wc_valid && c32isalnum ((mbc).wc))
231 #define mb_isalpha(mbc) ((mbc).wc_valid && c32isalpha ((mbc).wc))
232 #define mb_isblank(mbc) ((mbc).wc_valid && c32isblank ((mbc).wc))
233 #define mb_iscntrl(mbc) ((mbc).wc_valid && c32iscntrl ((mbc).wc))
234 #define mb_isdigit(mbc) ((mbc).wc_valid && c32isdigit ((mbc).wc))
235 #define mb_isgraph(mbc) ((mbc).wc_valid && c32isgraph ((mbc).wc))
236 #define mb_islower(mbc) ((mbc).wc_valid && c32islower ((mbc).wc))
237 #define mb_isprint(mbc) ((mbc).wc_valid && c32isprint ((mbc).wc))
238 #define mb_ispunct(mbc) ((mbc).wc_valid && c32ispunct ((mbc).wc))
239 #define mb_isspace(mbc) ((mbc).wc_valid && c32isspace ((mbc).wc))
240 #define mb_isupper(mbc) ((mbc).wc_valid && c32isupper ((mbc).wc))
241 #define mb_isxdigit(mbc) ((mbc).wc_valid && c32isxdigit ((mbc).wc))
243 /* Extra <wchar.h> function. */
245 /* Unprintable characters appear as a small box of width 1. */
246 #define MB_UNPRINTABLE_WIDTH 1
249 mb_width_aux (char32_t wc
)
251 int w
= c32width (wc
);
252 /* For unprintable characters, arbitrarily return 0 for control characters
253 and MB_UNPRINTABLE_WIDTH otherwise. */
254 return (w
>= 0 ? w
: c32iscntrl (wc
) ? 0 : MB_UNPRINTABLE_WIDTH
);
257 #define mb_width(mbc) \
258 ((mbc).wc_valid ? mb_width_aux ((mbc).wc) : MB_UNPRINTABLE_WIDTH)
261 #define mb_putc(mbc, stream) fwrite ((mbc).ptr, 1, (mbc).bytes, (stream))
263 #if defined GNULIB_MBFILE
265 # define mb_setascii(mbc, sc) \
266 ((mbc)->ptr = (mbc)->buf, (mbc)->bytes = 1, (mbc)->wc_valid = 1, \
267 (mbc)->wc = (mbc)->buf[0] = (sc))
270 /* Copying a character. */
272 mb_copy (mbchar_t
*new_mbc
, const mbchar_t
*old_mbc
)
274 #if defined GNULIB_MBFILE
275 if (old_mbc
->ptr
== &old_mbc
->buf
[0])
277 memcpy (&new_mbc
->buf
[0], &old_mbc
->buf
[0], old_mbc
->bytes
);
278 new_mbc
->ptr
= &new_mbc
->buf
[0];
282 new_mbc
->ptr
= old_mbc
->ptr
;
283 new_mbc
->bytes
= old_mbc
->bytes
;
284 if ((new_mbc
->wc_valid
= old_mbc
->wc_valid
))
285 new_mbc
->wc
= old_mbc
->wc
;
289 /* is_basic(c) tests whether the single-byte character c is
290 - in the ISO C "basic character set" or is one of '@', '$', and '`'
291 which ISO C 23 ยง 5.2.1.1.(1) guarantees to be single-byte and in
292 practice are safe to treat as basic in the execution character set,
294 - in the POSIX "portable character set", which
295 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06.html>
296 equally guarantees to be single-byte.
297 This is a convenience function, and is in this file only to share code
298 between mbiter.h, mbuiter.h, and mbfile.h. */
299 #if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
300 && ('$' == 36) && ('%' == 37) && ('&' == 38) && ('\'' == 39) \
301 && ('(' == 40) && (')' == 41) && ('*' == 42) && ('+' == 43) \
302 && (',' == 44) && ('-' == 45) && ('.' == 46) && ('/' == 47) \
303 && ('0' == 48) && ('1' == 49) && ('2' == 50) && ('3' == 51) \
304 && ('4' == 52) && ('5' == 53) && ('6' == 54) && ('7' == 55) \
305 && ('8' == 56) && ('9' == 57) && (':' == 58) && (';' == 59) \
306 && ('<' == 60) && ('=' == 61) && ('>' == 62) && ('?' == 63) \
307 && ('@' == 64) && ('A' == 65) && ('B' == 66) && ('C' == 67) \
308 && ('D' == 68) && ('E' == 69) && ('F' == 70) && ('G' == 71) \
309 && ('H' == 72) && ('I' == 73) && ('J' == 74) && ('K' == 75) \
310 && ('L' == 76) && ('M' == 77) && ('N' == 78) && ('O' == 79) \
311 && ('P' == 80) && ('Q' == 81) && ('R' == 82) && ('S' == 83) \
312 && ('T' == 84) && ('U' == 85) && ('V' == 86) && ('W' == 87) \
313 && ('X' == 88) && ('Y' == 89) && ('Z' == 90) && ('[' == 91) \
314 && ('\\' == 92) && (']' == 93) && ('^' == 94) && ('_' == 95) \
315 && ('`' == 96) && ('a' == 97) && ('b' == 98) && ('c' == 99) \
316 && ('d' == 100) && ('e' == 101) && ('f' == 102) && ('g' == 103) \
317 && ('h' == 104) && ('i' == 105) && ('j' == 106) && ('k' == 107) \
318 && ('l' == 108) && ('m' == 109) && ('n' == 110) && ('o' == 111) \
319 && ('p' == 112) && ('q' == 113) && ('r' == 114) && ('s' == 115) \
320 && ('t' == 116) && ('u' == 117) && ('v' == 118) && ('w' == 119) \
321 && ('x' == 120) && ('y' == 121) && ('z' == 122) && ('{' == 123) \
322 && ('|' == 124) && ('}' == 125) && ('~' == 126)
323 /* The character set is ISO-646, not EBCDIC. */
324 # define IS_BASIC_ASCII 1
326 /* All locale encodings (see localcharset.h) map the characters 0x00..0x7F
327 to U+0000..U+007F, like ASCII, except for
328 CP864 different mapping of '%'
329 SHIFT_JIS different mappings of 0x5C, 0x7E
330 JOHAB different mapping of 0x5C
331 However, these characters in the range 0x20..0x7E are in the ISO C
332 "basic character set" and in the POSIX "portable character set", which
333 ISO C and POSIX guarantee to be single-byte. Thus, locales with these
334 encodings are not POSIX compliant. And they are most likely not in use
335 any more (as of 2023). */
336 # define is_basic(c) ((unsigned char) (c) < 0x80)
346 case '\007': case '\010':
347 case '\t': case '\n': case '\v': case '\f': case '\r':
348 case ' ': case '!': case '"': case '#': case '$': case '%':
349 case '&': case '\'': case '(': case ')': case '*':
350 case '+': case ',': case '-': case '.': case '/':
351 case '0': case '1': case '2': case '3': case '4':
352 case '5': case '6': case '7': case '8': case '9':
353 case ':': case ';': case '<': case '=': case '>':
355 case 'A': case 'B': case 'C': case 'D': case 'E':
356 case 'F': case 'G': case 'H': case 'I': case 'J':
357 case 'K': case 'L': case 'M': case 'N': case 'O':
358 case 'P': case 'Q': case 'R': case 'S': case 'T':
359 case 'U': case 'V': case 'W': case 'X': case 'Y':
361 case '[': case '\\': case ']': case '^': case '_': case '`':
362 case 'a': case 'b': case 'c': case 'd': case 'e':
363 case 'f': case 'g': case 'h': case 'i': case 'j':
364 case 'k': case 'l': case 'm': case 'n': case 'o':
365 case 'p': case 'q': case 'r': case 's': case 't':
366 case 'u': case 'v': case 'w': case 'x': case 'y':
367 case 'z': case '{': case '|': case '}': case '~':
381 _GL_INLINE_HEADER_END
383 #endif /* _MBCHAR_H */