1 /* Multibyte character data type.
2 Copyright (C) 2001, 2005-2006 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program 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 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Written by Bruno Haible <bruno@clisp.org>. */
20 /* A multibyte character is a short subsequence of a char* string,
21 representing a single wide character.
23 We use multibyte characters instead of wide characters because of
25 1) correct multibyte handling, i.e. operate according to the LC_CTYPE
27 2) ease of maintenance, i.e. the maintainer needs not know all details
28 of the ISO C 99 standard,
29 3) don't fail grossly if the input is not in the encoding set by the
30 locale, because often different encodings are in use in the same
31 countries (ISO-8859-1/UTF-8, EUC-JP/Shift_JIS, ...),
32 4) fast in the case of ASCII characters,
33 5) portability, i.e. don't make unportable assumptions about wchar_t.
35 Multibyte characters are only accessed through the mb* macros.
38 return a pointer to the beginning of the multibyte sequence.
41 returns the number of bytes occupied by the multibyte sequence.
45 returns true if mbc is the standard ASCII character sc.
48 returns true if mbc is the nul character.
51 returns a positive, zero, or negative value depending on whether mbc1
52 sorts after, same or before mbc2.
54 mb_casecmp (mbc1, mbc2)
55 returns a positive, zero, or negative value depending on whether mbc1
56 sorts after, same or before mbc2, modulo upper/lowercase conversion.
59 returns true if mbc1 and mbc2 are equal.
61 mb_caseequal (mbc1, mbc2)
62 returns true if mbc1 and mbc2 are equal modulo upper/lowercase conversion.
65 returns true if mbc is alphanumeric.
68 returns true if mbc is alphabetic.
71 returns true if mbc is plain ASCII.
74 returns true if mbc is a blank.
77 returns true if mbc is a control character.
80 returns true if mbc is a decimal digit.
83 returns true if mbc is a graphic character.
86 returns true if mbc is lowercase.
89 returns true if mbc is a printable character.
92 returns true if mbc is a punctuation character.
95 returns true if mbc is a space character.
98 returns true if mbc is uppercase.
101 returns true if mbc is a hexadecimal digit.
104 returns the number of columns on the output device occupied by mbc.
107 mb_putc (mbc, stream)
108 outputs mbc on stream, a byte oriented FILE stream opened for output.
110 mb_setascii (&mbc, sc)
111 assigns the standard ASCII character sc to mbc.
113 mb_copy (&destmbc, &srcmbc)
114 copies srcmbc to destmbc.
116 Here are the function prototypes of the macros.
118 extern const char * mb_ptr (const mbchar_t mbc);
119 extern size_t mb_len (const mbchar_t mbc);
120 extern bool mb_iseq (const mbchar_t mbc, char sc);
121 extern bool mb_isnul (const mbchar_t mbc);
122 extern int mb_cmp (const mbchar_t mbc1, const mbchar_t mbc2);
123 extern int mb_casecmp (const mbchar_t mbc1, const mbchar_t mbc2);
124 extern bool mb_equal (const mbchar_t mbc1, const mbchar_t mbc2);
125 extern bool mb_caseequal (const mbchar_t mbc1, const mbchar_t mbc2);
126 extern bool mb_isalnum (const mbchar_t mbc);
127 extern bool mb_isalpha (const mbchar_t mbc);
128 extern bool mb_isascii (const mbchar_t mbc);
129 extern bool mb_isblank (const mbchar_t mbc);
130 extern bool mb_iscntrl (const mbchar_t mbc);
131 extern bool mb_isdigit (const mbchar_t mbc);
132 extern bool mb_isgraph (const mbchar_t mbc);
133 extern bool mb_islower (const mbchar_t mbc);
134 extern bool mb_isprint (const mbchar_t mbc);
135 extern bool mb_ispunct (const mbchar_t mbc);
136 extern bool mb_isspace (const mbchar_t mbc);
137 extern bool mb_isupper (const mbchar_t mbc);
138 extern bool mb_isxdigit (const mbchar_t mbc);
139 extern int mb_width (const mbchar_t mbc);
140 extern void mb_putc (const mbchar_t mbc, FILE *stream);
141 extern void mb_setascii (mbchar_t *new, char sc);
142 extern void mb_copy (mbchar_t *new, const mbchar_t *old);
151 /* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
153 BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
159 /* BeOS 5 has the functions but no <wctype.h>. */
163 /* FreeBSD 4.4 to 4.11 has <wctype.h> but lacks the functions.
164 Assume all 12 functions are implemented the same way, or not at all. */
165 #if !defined iswalnum && !HAVE_ISWCNTRL
169 return (wc >= 0 && wc < 128
170 ? (wc >= '0' && wc <= '9') || ((wc & ~0x20) >= 'A' && (wc & ~0x20) <= 'Z')
173 # define iswalnum iswalnum
175 #if !defined iswalpha && !HAVE_ISWCNTRL
179 return (wc >= 0 && wc < 128
180 ? (wc & ~0x20) >= 'A' && (wc & ~0x20) <= 'Z'
183 # define iswalpha iswalpha
185 #if !defined iswblank && !HAVE_ISWCNTRL
189 return (wc >= 0 && wc < 128
190 ? wc == ' ' || wc == '\t'
193 # define iswblank iswblank
195 #if !defined iswcntrl && !HAVE_ISWCNTRL
199 return (wc >= 0 && wc < 128
200 ? (wc & ~0x1f) == 0 || wc == 0x7f
203 # define iswcntrl iswcntrl
205 #if !defined iswdigit && !HAVE_ISWCNTRL
209 return (wc >= '0' && wc <= '9');
211 # define iswdigit iswdigit
213 #if !defined iswgraph && !HAVE_ISWCNTRL
217 return (wc >= 0 && wc < 128
218 ? wc >= '!' && wc <= '~'
221 # define iswgraph iswgraph
223 #if !defined iswlower && !HAVE_ISWCNTRL
227 return (wc >= 0 && wc < 128
228 ? wc >= 'a' && wc <= 'z'
231 # define iswlower iswlower
233 #if !defined iswprint && !HAVE_ISWCNTRL
237 return (wc >= 0 && wc < 128
238 ? wc >= ' ' && wc <= '~'
241 # define iswprint iswprint
243 #if !defined iswpunct && !HAVE_ISWCNTRL
247 return (wc >= 0 && wc < 128
248 ? wc >= '!' && wc <= '~'
249 && !((wc >= '0' && wc <= '9')
250 || ((wc & ~0x20) >= 'A' && (wc & ~0x20) <= 'Z'))
253 # define iswpunct iswpunct
255 #if !defined iswspace && !HAVE_ISWCNTRL
259 return (wc >= 0 && wc < 128
260 ? wc == ' ' || wc == '\t'
261 || wc == '\n' || wc == '\v' || wc == '\f' || wc == '\r'
264 # define iswspace iswspace
266 #if !defined iswupper && !HAVE_ISWCNTRL
270 return (wc >= 0 && wc < 128
271 ? wc >= 'A' && wc <= 'Z'
274 # define iswupper iswupper
276 #if !defined iswxdigit && !HAVE_ISWCNTRL
278 iswxdigit (wint_t wc)
280 return (wc >= '0' && wc <= '9') || ((wc & ~0x20) >= 'A' && (wc & ~0x20) <= 'F');
282 # define iswxdigit iswxdigit
287 #define MBCHAR_BUF_SIZE 24
291 const char *ptr; /* pointer to current character */
292 size_t bytes; /* number of bytes of current character, > 0 */
293 bool wc_valid; /* true if wc is a valid wide character */
294 wchar_t wc; /* if wc_valid: the current character */
295 char buf[MBCHAR_BUF_SIZE]; /* room for the bytes, used for file input only */
298 /* EOF (not a real character) is represented with bytes = 0 and
301 typedef struct mbchar mbchar_t;
303 /* Access the current character. */
304 #define mb_ptr(mbc) ((mbc).ptr)
305 #define mb_len(mbc) ((mbc).bytes)
307 /* Comparison of characters. */
308 #define mb_iseq(mbc, sc) ((mbc).wc_valid && (mbc).wc == (sc))
309 #define mb_isnul(mbc) ((mbc).wc_valid && (mbc).wc == 0)
310 #define mb_cmp(mbc1, mbc2) \
313 ? (int) (mbc1).wc - (int) (mbc2).wc \
317 : (mbc1).bytes == (mbc2).bytes \
318 ? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
319 : (mbc1).bytes < (mbc2).bytes \
320 ? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
321 : (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
322 #define mb_casecmp(mbc1, mbc2) \
325 ? (int) towlower ((mbc1).wc) - (int) towlower ((mbc2).wc) \
329 : (mbc1).bytes == (mbc2).bytes \
330 ? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
331 : (mbc1).bytes < (mbc2).bytes \
332 ? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
333 : (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
334 #define mb_equal(mbc1, mbc2) \
335 ((mbc1).wc_valid && (mbc2).wc_valid \
336 ? (mbc1).wc == (mbc2).wc \
337 : (mbc1).bytes == (mbc2).bytes \
338 && memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
339 #define mb_caseequal(mbc1, mbc2) \
340 ((mbc1).wc_valid && (mbc2).wc_valid \
341 ? towlower ((mbc1).wc) == towlower ((mbc2).wc) \
342 : (mbc1).bytes == (mbc2).bytes \
343 && memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
345 /* <ctype.h>, <wctype.h> classification. */
346 #define mb_isascii(mbc) \
347 ((mbc).wc_valid && (mbc).wc >= 0 && (mbc).wc <= 127)
348 #define mb_isalnum(mbc) ((mbc).wc_valid && iswalnum ((mbc).wc))
349 #define mb_isalpha(mbc) ((mbc).wc_valid && iswalpha ((mbc).wc))
350 #define mb_isblank(mbc) ((mbc).wc_valid && iswblank ((mbc).wc))
351 #define mb_iscntrl(mbc) ((mbc).wc_valid && iswcntrl ((mbc).wc))
352 #define mb_isdigit(mbc) ((mbc).wc_valid && iswdigit ((mbc).wc))
353 #define mb_isgraph(mbc) ((mbc).wc_valid && iswgraph ((mbc).wc))
354 #define mb_islower(mbc) ((mbc).wc_valid && iswlower ((mbc).wc))
355 #define mb_isprint(mbc) ((mbc).wc_valid && iswprint ((mbc).wc))
356 #define mb_ispunct(mbc) ((mbc).wc_valid && iswpunct ((mbc).wc))
357 #define mb_isspace(mbc) ((mbc).wc_valid && iswspace ((mbc).wc))
358 #define mb_isupper(mbc) ((mbc).wc_valid && iswupper ((mbc).wc))
359 #define mb_isxdigit(mbc) ((mbc).wc_valid && iswxdigit ((mbc).wc))
361 /* Extra <wchar.h> function. */
363 /* Unprintable characters appear as a small box of width 1. */
364 #define MB_UNPRINTABLE_WIDTH 1
367 mb_width_aux (wint_t wc)
369 int w = wcwidth (wc);
370 /* For unprintable characters, arbitrarily return 0 for control characters
371 and MB_UNPRINTABLE_WIDTH otherwise. */
372 return (w >= 0 ? w : iswcntrl (wc) ? 0 : MB_UNPRINTABLE_WIDTH);
375 #define mb_width(mbc) \
376 ((mbc).wc_valid ? mb_width_aux ((mbc).wc) : MB_UNPRINTABLE_WIDTH)
379 #define mb_putc(mbc, stream) fwrite ((mbc).ptr, 1, (mbc).bytes, (stream))
382 #define mb_setascii(mbc, sc) \
383 ((mbc)->ptr = (mbc)->buf, (mbc)->bytes = 1, (mbc)->wc_valid = 1, \
384 (mbc)->wc = (mbc)->buf[0] = (sc))
386 /* Copying a character. */
388 mb_copy (mbchar_t *new_mbc, const mbchar_t *old_mbc)
390 if (old_mbc->ptr == &old_mbc->buf[0])
392 memcpy (&new_mbc->buf[0], &old_mbc->buf[0], old_mbc->bytes);
393 new_mbc->ptr = &new_mbc->buf[0];
396 new_mbc->ptr = old_mbc->ptr;
397 new_mbc->bytes = old_mbc->bytes;
398 if ((new_mbc->wc_valid = old_mbc->wc_valid))
399 new_mbc->wc = old_mbc->wc;
403 /* is_basic(c) tests whether the single-byte character c is in the
404 ISO C "basic character set".
405 This is a convenience function, and is in this file only to share code
406 between mbiter_multi.h and mbfile_multi.h. */
407 #if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
408 && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
409 && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
410 && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
411 && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
412 && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
413 && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
414 && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
415 && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
416 && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
417 && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
418 && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
419 && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
420 && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
421 && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
422 && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
423 && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
424 && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
425 && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
426 && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
427 && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
428 && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
429 && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)
430 /* The character set is ISO-646, not EBCDIC. */
431 # define IS_BASIC_ASCII 1
433 extern const unsigned int is_basic_table[];
438 return (is_basic_table [(unsigned char) c >> 5] >> ((unsigned char) c & 31))
449 case '\t': case '\v': case '\f':
450 case ' ': case '!': case '"': case '#': case '%':
451 case '&': case '\'': case '(': case ')': case '*':
452 case '+': case ',': case '-': case '.': case '/':
453 case '0': case '1': case '2': case '3': case '4':
454 case '5': case '6': case '7': case '8': case '9':
455 case ':': case ';': case '<': case '=': case '>':
457 case 'A': case 'B': case 'C': case 'D': case 'E':
458 case 'F': case 'G': case 'H': case 'I': case 'J':
459 case 'K': case 'L': case 'M': case 'N': case 'O':
460 case 'P': case 'Q': case 'R': case 'S': case 'T':
461 case 'U': case 'V': case 'W': case 'X': case 'Y':
463 case '[': case '\\': case ']': case '^': case '_':
464 case 'a': case 'b': case 'c': case 'd': case 'e':
465 case 'f': case 'g': case 'h': case 'i': case 'j':
466 case 'k': case 'l': case 'm': case 'n': case 'o':
467 case 'p': case 'q': case 'r': case 's': case 't':
468 case 'u': case 'v': case 'w': case 'x': case 'y':
469 case 'z': case '{': case '|': case '}': case '~':
478 #endif /* _MBCHAR_H */