]> git.ipfire.org Git - thirdparty/bash.git/blob - include/shmbutil.h
835fb80cdb6ee23f2e70216fb1fb8bb3e438bd82
[thirdparty/bash.git] / include / shmbutil.h
1 /* shmbutil.h -- utility functions for multibyte characters. */
2
3 /* Copyright (C) 2002-2019 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #if !defined (_SH_MBUTIL_H_)
22 #define _SH_MBUTIL_H_
23
24 #include "stdc.h"
25
26 /* Include config.h for HANDLE_MULTIBYTE */
27 #include <config.h>
28
29 #if defined (HANDLE_MULTIBYTE)
30 #include "shmbchar.h"
31
32 extern size_t xwcsrtombs PARAMS((char *, const wchar_t **, size_t, mbstate_t *));
33 extern size_t xmbsrtowcs PARAMS((wchar_t *, const char **, size_t, mbstate_t *));
34 extern size_t xdupmbstowcs PARAMS((wchar_t **, char ***, const char *));
35
36 extern size_t mbstrlen PARAMS((const char *));
37
38 extern char *xstrchr PARAMS((const char *, int));
39
40 extern int locale_mb_cur_max; /* XXX */
41 extern int locale_utf8locale; /* XXX */
42
43 #ifndef MB_INVALIDCH
44 #define MB_INVALIDCH(x) ((x) == (size_t)-1 || (x) == (size_t)-2)
45 #define MB_NULLWCH(x) ((x) == 0)
46 #endif
47
48 #define MBSLEN(s) (((s) && (s)[0]) ? ((s)[1] ? mbstrlen (s) : 1) : 0)
49 #define MB_STRLEN(s) ((MB_CUR_MAX > 1) ? MBSLEN (s) : STRLEN (s))
50
51 #define MBLEN(s, n) ((MB_CUR_MAX > 1) ? mblen ((s), (n)) : 1)
52 #define MBRLEN(s, n, p) ((MB_CUR_MAX > 1) ? mbrlen ((s), (n), (p)) : 1)
53
54 #define UTF8_SINGLEBYTE(c) (((c) & 0x80) == 0)
55 #define UTF8_MBFIRSTCHAR(c) (((c) & 0xc0) == 0xc0)
56 #define UTF8_MBCHAR(c) (((c) & 0xc0) == 0x80)
57
58 #else /* !HANDLE_MULTIBYTE */
59
60 #undef MB_LEN_MAX
61 #undef MB_CUR_MAX
62
63 #define MB_LEN_MAX 1
64 #define MB_CUR_MAX 1
65
66 #undef xstrchr
67 #define xstrchr(s, c) strchr(s, c)
68
69 #ifndef MB_INVALIDCH
70 #define MB_INVALIDCH(x) (0)
71 #define MB_NULLWCH(x) (0)
72 #endif
73
74 #define MB_STRLEN(s) (STRLEN(s))
75
76 #define MBLEN(s, n) 1
77 #define MBRLEN(s, n, p) 1
78
79 #ifndef wchar_t
80 # define wchar_t int
81 #endif
82
83 #define UTF8_SINGLEBYTE(c) (1)
84 #define UTF8_MBFIRSTCHAR(c) (0)
85
86 #endif /* !HANDLE_MULTIBYTE */
87
88 /* Declare and initialize a multibyte state. Call must be terminated
89 with `;'. */
90 #if defined (HANDLE_MULTIBYTE)
91 # define DECLARE_MBSTATE \
92 mbstate_t state; \
93 memset (&state, '\0', sizeof (mbstate_t))
94 #else
95 # define DECLARE_MBSTATE
96 #endif /* !HANDLE_MULTIBYTE */
97
98 /* Initialize or reinitialize a multibyte state named `state'. Call must be
99 terminated with `;'. */
100 #if defined (HANDLE_MULTIBYTE)
101 # define INITIALIZE_MBSTATE memset (&state, '\0', sizeof (mbstate_t))
102 #else
103 # define INITIALIZE_MBSTATE
104 #endif /* !HANDLE_MULTIBYTE */
105
106 /* Advance one (possibly multi-byte) character in string _STR of length
107 _STRSIZE, starting at index _I. STATE must have already been declared. */
108 #if defined (HANDLE_MULTIBYTE)
109 # define ADVANCE_CHAR(_str, _strsize, _i) \
110 do \
111 { \
112 if (locale_mb_cur_max > 1) \
113 { \
114 mbstate_t state_bak; \
115 size_t mblength; \
116 int _f; \
117 \
118 _f = is_basic ((_str)[_i]); \
119 if (_f) \
120 mblength = 1; \
121 else if (locale_utf8locale && (((_str)[_i] & 0x80) == 0)) \
122 mblength = (_str)[_i] != 0; \
123 else \
124 { \
125 state_bak = state; \
126 mblength = mbrlen ((_str) + (_i), (_strsize) - (_i), &state); \
127 } \
128 \
129 if (mblength == (size_t)-2 || mblength == (size_t)-1) \
130 { \
131 state = state_bak; \
132 (_i)++; \
133 } \
134 else if (mblength == 0) \
135 (_i)++; \
136 else \
137 (_i) += mblength; \
138 } \
139 else \
140 (_i)++; \
141 } \
142 while (0)
143 #else
144 # define ADVANCE_CHAR(_str, _strsize, _i) (_i)++
145 #endif /* !HANDLE_MULTIBYTE */
146
147 /* Advance one (possibly multibyte) character in the string _STR of length
148 _STRSIZE.
149 SPECIAL: assume that _STR will be incremented by 1 after this call. */
150 #if defined (HANDLE_MULTIBYTE)
151 # define ADVANCE_CHAR_P(_str, _strsize) \
152 do \
153 { \
154 if (locale_mb_cur_max > 1) \
155 { \
156 mbstate_t state_bak; \
157 size_t mblength; \
158 int _f; \
159 \
160 _f = is_basic (*(_str)); \
161 if (_f) \
162 mblength = 1; \
163 else if (locale_utf8locale && ((*(_str) & 0x80) == 0)) \
164 mblength = *(_str) != 0; \
165 else \
166 { \
167 state_bak = state; \
168 mblength = mbrlen ((_str), (_strsize), &state); \
169 } \
170 \
171 if (mblength == (size_t)-2 || mblength == (size_t)-1) \
172 { \
173 state = state_bak; \
174 mblength = 1; \
175 } \
176 else \
177 (_str) += (mblength < 1) ? 0 : (mblength - 1); \
178 } \
179 } \
180 while (0)
181 #else
182 # define ADVANCE_CHAR_P(_str, _strsize)
183 #endif /* !HANDLE_MULTIBYTE */
184
185 /* Back up one (possibly multi-byte) character in string _STR of length
186 _STRSIZE, starting at index _I. STATE must have already been declared. */
187 #if defined (HANDLE_MULTIBYTE)
188 # define BACKUP_CHAR(_str, _strsize, _i) \
189 do \
190 { \
191 if (locale_mb_cur_max > 1) \
192 { \
193 mbstate_t state_bak; \
194 size_t mblength; \
195 int _x, _p; /* _x == temp index into string, _p == prev index */ \
196 \
197 _x = _p = 0; \
198 while (_x < (_i)) \
199 { \
200 state_bak = state; \
201 mblength = mbrlen ((_str) + (_x), (_strsize) - (_x), &state); \
202 \
203 if (mblength == (size_t)-2 || mblength == (size_t)-1) \
204 { \
205 state = state_bak; \
206 _x++; \
207 } \
208 else if (mblength == 0) \
209 _x++; \
210 else \
211 { \
212 _p = _x; /* _p == start of prev mbchar */ \
213 _x += mblength; \
214 } \
215 } \
216 (_i) = _p; \
217 } \
218 else \
219 (_i)--; \
220 } \
221 while (0)
222 #else
223 # define BACKUP_CHAR(_str, _strsize, _i) (_i)--
224 #endif /* !HANDLE_MULTIBYTE */
225
226 /* Back up one (possibly multibyte) character in the string _BASE of length
227 _STRSIZE starting at _STR (_BASE <= _STR <= (_BASE + _STRSIZE) ).
228 SPECIAL: DO NOT assume that _STR will be decremented by 1 after this call. */
229 #if defined (HANDLE_MULTIBYTE)
230 # define BACKUP_CHAR_P(_base, _strsize, _str) \
231 do \
232 { \
233 if (locale_mb_cur_max > 1) \
234 { \
235 mbstate_t state_bak; \
236 size_t mblength; \
237 char *_x, _p; /* _x == temp pointer into string, _p == prev pointer */ \
238 \
239 _x = _p = _base; \
240 while (_x < (_str)) \
241 { \
242 state_bak = state; \
243 mblength = mbrlen (_x, (_strsize) - _x, &state); \
244 \
245 if (mblength == (size_t)-2 || mblength == (size_t)-1) \
246 { \
247 state = state_bak; \
248 _x++; \
249 } \
250 else if (mblength == 0) \
251 _x++; \
252 else \
253 { \
254 _p = _x; /* _p == start of prev mbchar */ \
255 _x += mblength; \
256 } \
257 } \
258 (_str) = _p; \
259 } \
260 else \
261 (_str)--; \
262 } \
263 while (0)
264 #else
265 # define BACKUP_CHAR_P(_base, _strsize, _str) (_str)--
266 #endif /* !HANDLE_MULTIBYTE */
267
268 /* Copy a single character from the string _SRC to the string _DST.
269 _SRCEND is a pointer to the end of _SRC. */
270 #if defined (HANDLE_MULTIBYTE)
271 # define COPY_CHAR_P(_dst, _src, _srcend) \
272 do \
273 { \
274 if (locale_mb_cur_max > 1) \
275 { \
276 mbstate_t state_bak; \
277 size_t mblength; \
278 int _k; \
279 \
280 _k = is_basic (*(_src)); \
281 if (_k) \
282 mblength = 1; \
283 else if (locale_utf8locale && ((*(_src) & 0x80) == 0)) \
284 mblength = *(_src) != 0; \
285 else \
286 { \
287 state_bak = state; \
288 mblength = mbrlen ((_src), (_srcend) - (_src), &state); \
289 } \
290 if (mblength == (size_t)-2 || mblength == (size_t)-1) \
291 { \
292 state = state_bak; \
293 mblength = 1; \
294 } \
295 else \
296 mblength = (mblength < 1) ? 1 : mblength; \
297 \
298 for (_k = 0; _k < mblength; _k++) \
299 *(_dst)++ = *(_src)++; \
300 } \
301 else \
302 *(_dst)++ = *(_src)++; \
303 } \
304 while (0)
305 #else
306 # define COPY_CHAR_P(_dst, _src, _srcend) *(_dst)++ = *(_src)++
307 #endif /* !HANDLE_MULTIBYTE */
308
309 /* Copy a single character from the string _SRC at index _SI to the string
310 _DST at index _DI. _SRCEND is a pointer to the end of _SRC. */
311 #if defined (HANDLE_MULTIBYTE)
312 # define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) \
313 do \
314 { \
315 if (locale_mb_cur_max > 1) \
316 { \
317 mbstate_t state_bak; \
318 size_t mblength; \
319 int _k; \
320 \
321 _k = is_basic (*((_src) + (_si))); \
322 if (_k) \
323 mblength = 1; \
324 else \
325 {\
326 state_bak = state; \
327 mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src)+(_si)), &state); \
328 } \
329 if (mblength == (size_t)-2 || mblength == (size_t)-1) \
330 { \
331 state = state_bak; \
332 mblength = 1; \
333 } \
334 else \
335 mblength = (mblength < 1) ? 1 : mblength; \
336 \
337 for (_k = 0; _k < mblength; _k++) \
338 _dst[_di++] = _src[_si++]; \
339 } \
340 else \
341 _dst[_di++] = _src[_si++]; \
342 } \
343 while (0)
344 #else
345 # define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) _dst[_di++] = _src[_si++]
346 #endif /* !HANDLE_MULTIBYTE */
347
348 /****************************************************************
349 * *
350 * The following are only guaranteed to work in subst.c *
351 * *
352 ****************************************************************/
353
354 #if defined (HANDLE_MULTIBYTE)
355 # define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \
356 do \
357 { \
358 if (locale_mb_cur_max > 1) \
359 { \
360 mbstate_t state_bak; \
361 size_t mblength; \
362 int _i; \
363 \
364 _i = is_basic (*((_src) + (_si))); \
365 if (_i) \
366 mblength = 1; \
367 else \
368 { \
369 state_bak = state; \
370 mblength = mbrlen ((_src) + (_si), (_slen) - (_si), &state); \
371 } \
372 if (mblength == (size_t)-2 || mblength == (size_t)-1) \
373 { \
374 state = state_bak; \
375 mblength = 1; \
376 } \
377 else \
378 mblength = (mblength < 1) ? 1 : mblength; \
379 \
380 temp = xmalloc (mblength + 2); \
381 temp[0] = _escchar; \
382 for (_i = 0; _i < mblength; _i++) \
383 temp[_i + 1] = _src[_si++]; \
384 temp[mblength + 1] = '\0'; \
385 \
386 goto add_string; \
387 } \
388 else \
389 { \
390 _dst[0] = _escchar; \
391 _dst[1] = _sc; \
392 } \
393 } \
394 while (0)
395 #else
396 # define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \
397 _dst[0] = _escchar; \
398 _dst[1] = _sc
399 #endif /* !HANDLE_MULTIBYTE */
400
401 #if defined (HANDLE_MULTIBYTE)
402 # define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \
403 do \
404 { \
405 if (locale_mb_cur_max > 1) \
406 { \
407 mbstate_t state_bak; \
408 size_t mblength; \
409 int _i; \
410 \
411 _i = is_basic (*((_src) + (_si))); \
412 if (_i) \
413 mblength = 1; \
414 else \
415 { \
416 state_bak = state; \
417 mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src) + (_si)), &state); \
418 } \
419 if (mblength == (size_t)-2 || mblength == (size_t)-1) \
420 { \
421 state = state_bak; \
422 mblength = 1; \
423 } \
424 else \
425 mblength = (mblength < 1) ? 1 : mblength; \
426 \
427 FASTCOPY(((_src) + (_si)), (_dst), mblength); \
428 \
429 (_dst) += mblength; \
430 (_si) += mblength; \
431 } \
432 else \
433 { \
434 *(_dst)++ = _src[(_si)]; \
435 (_si)++; \
436 } \
437 } \
438 while (0)
439 #else
440 # define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \
441 *(_dst)++ = _src[(_si)]; \
442 (_si)++
443 #endif /* !HANDLE_MULTIBYTE */
444
445 #if HANDLE_MULTIBYTE
446 # define SADD_MBCHAR(_dst, _src, _si, _srcsize) \
447 do \
448 { \
449 if (locale_mb_cur_max > 1) \
450 { \
451 int i; \
452 mbstate_t state_bak; \
453 size_t mblength; \
454 \
455 i = is_basic (*((_src) + (_si))); \
456 if (i) \
457 mblength = 1; \
458 else if (locale_utf8locale && (((_src)[_si] & 0x80) == 0)) \
459 mblength = (_src)[_si] != 0; \
460 else \
461 { \
462 state_bak = state; \
463 mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
464 } \
465 if (mblength == (size_t)-1 || mblength == (size_t)-2) \
466 { \
467 state = state_bak; \
468 mblength = 1; \
469 } \
470 if (mblength < 1) \
471 mblength = 1; \
472 \
473 _dst = (char *)xmalloc (mblength + 1); \
474 for (i = 0; i < mblength; i++) \
475 (_dst)[i] = (_src)[(_si)++]; \
476 (_dst)[mblength] = '\0'; \
477 \
478 goto add_string; \
479 } \
480 } \
481 while (0)
482
483 #else
484 # define SADD_MBCHAR(_dst, _src, _si, _srcsize)
485 #endif
486
487 /* Watch out when using this -- it's just straight textual substitution */
488 #if defined (HANDLE_MULTIBYTE)
489 # define SADD_MBQCHAR_BODY(_dst, _src, _si, _srcsize) \
490 \
491 int i; \
492 mbstate_t state_bak; \
493 size_t mblength; \
494 \
495 i = is_basic (*((_src) + (_si))); \
496 if (i) \
497 mblength = 1; \
498 else if (locale_utf8locale && (((_src)[_si] & 0x80) == 0)) \
499 mblength = (_src)[_si] != 0; \
500 else \
501 { \
502 state_bak = state; \
503 mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
504 } \
505 if (mblength == (size_t)-1 || mblength == (size_t)-2) \
506 { \
507 state = state_bak; \
508 mblength = 1; \
509 } \
510 if (mblength < 1) \
511 mblength = 1; \
512 \
513 (_dst) = (char *)xmalloc (mblength + 2); \
514 (_dst)[0] = CTLESC; \
515 for (i = 0; i < mblength; i++) \
516 (_dst)[i+1] = (_src)[(_si)++]; \
517 (_dst)[mblength+1] = '\0'; \
518 \
519 goto add_string
520
521 # define SADD_MBCHAR_BODY(_dst, _src, _si, _srcsize) \
522 \
523 int i; \
524 mbstate_t state_bak; \
525 size_t mblength; \
526 \
527 i = is_basic (*((_src) + (_si))); \
528 if (i) \
529 mblength = 1; \
530 else \
531 { \
532 state_bak = state; \
533 mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
534 } \
535 if (mblength == (size_t)-1 || mblength == (size_t)-2) \
536 { \
537 state = state_bak; \
538 mblength = 1; \
539 } \
540 if (mblength < 1) \
541 mblength = 1; \
542 \
543 (_dst) = (char *)xmalloc (mblength + 1); \
544 for (i = 0; i < mblength; i++) \
545 (_dst)[i+1] = (_src)[(_si)++]; \
546 (_dst)[mblength+1] = '\0'; \
547 \
548 goto add_string
549
550 #endif /* HANDLE_MULTIBYTE */
551 #endif /* _SH_MBUTIL_H_ */