1 /*-
2 * Copyright (c) 2006, 2007, 2008
3 * Thorsten Glaser <tg@mirbsd.org>
4 *
5 * Provided that these terms and disclaimer and all copyright notices
6 * are retained or reproduced in an accompanying document, permission
7 * is granted to deal in this work without restriction, including un-
8 * limited rights to use, publicly perform, distribute, sell, modify,
9 * merge, give away, or sublicence.
10 *
11 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
12 * the utmost extent permitted by applicable law, neither express nor
13 * implied; without malicious intent or gross negligence. In no event
14 * may a licensor, author or contributor be held liable for indirect,
15 * direct, other damage, loss, or other issues arising in any way out
16 * of dealing in the work, even if advised of the possibility of such
17 * damage or existence of a defect, except proven that it results out
18 * of said person's immediate fault when using the work as intended.
19 *
20 * The author reserves the right to steward the OPTU encoding forms.
21 */
22
23 #include <errno.h>
24 #include <wchar.h>
25
26 __RCSID("$MirOS: src/lib/libc/i18n/wcsrtombs.c,v 1.10 2014/02/09 22:35:53 tg Exp $");
27
28 #ifdef WCSNRTOMBS
29 size_t
wcsnrtombs(char * dst,const wchar_t ** src,size_t max,size_t len,mbstate_t * ps)30 wcsnrtombs(char *dst, const wchar_t **src, size_t max, size_t len, mbstate_t *ps)
31 #else
32 size_t
33 wcsrtombs(char *dst, const wchar_t **src, size_t len, mbstate_t *ps)
34 #endif
35 {
36 static mbstate_t internal_mbstate = { 0, 0 }; /* if ps == NULL */
37 const wchar_t *s = *src;
38 unsigned char *d = (unsigned char *)dst;
39 wint_t wc /* shut up gcc */ = 0;
40 uint8_t count;
41
42 /* make sure we can at least write one output byte */
43 if ((dst != NULL) && (len == 0))
44 return (0);
45
46 if (__predict_false(ps == NULL))
47 ps = &internal_mbstate;
48
49 if ((count = ps->count)) {
50 wc = ps->value;
51 /* process remnants */
52 goto process_state;
53 }
54
55 process_firstbyte:
56 /* count is zero here; devour an input wide character */
57 #ifdef WCSNRTOMBS
58 if (s >= (*src + max))
59 goto empty_buf;
60 #endif
61 wc = *s++;
62 /* create the first output byte and state information from it */
63 if (__predict_false(wc > WCHAR_MAX)) {
64 errno = EILSEQ;
65 return ((size_t)(-1));
66 } else if (__predict_true(wc < 0x80 || iswoctet(wc))) {
67 if (dst != NULL)
68 *d = wc & 0xFF;
69 /* count is already 0 */
70 } else if (wc < 0x0800) {
71 if (dst != NULL)
72 *d = (wc >> 6) | 0xC0;
73 count = 1;
74 } else {
75 if (dst != NULL)
76 *d = (wc >> 12) | 0xE0;
77 count = 2;
78 }
79 /* account the output byte, except if it's the terminating NUL */
80 if (wc > 0)
81 ++d;
82 /* at this point, we have written an output byte */
83 --len;
84
85 process_state:
86 /* entering with len >= 0, count + wc containing state info */
87 while (__predict_false((count > 0) && ((len > 0) || (dst == NULL)))) {
88 --count;
89 if (dst != NULL)
90 *d = ((wc >> (6 * count)) & 0x3F) | 0x80;
91 ++d;
92 --len;
93 }
94
95 /* here: either len == 0 or count == 0 (or both!) */
96 if (__predict_false(wc == 0))
97 /* last character was a terminating NUL, count == 0 */
98 s = NULL;
99 else if (__predict_true(count == 0))
100 /* so, if there's still output space left or we ignore it */
101 if ((len > 0) || (dst == NULL))
102 /* loop on to the next full input wide character */
103 goto process_firstbyte;
104
105 #ifdef WCSNRTOMBS
106 empty_buf:
107 #endif
108 if (dst != NULL) {
109 *src = s;
110 /* save state information for restarting */
111 ps->count = count;
112 ps->value = wc;
113 }
114 return ((char *)d - dst);
115 }
116