xref: /haiku/src/system/libroot/posix/wchar/wcsrtombs.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
1 /*
2 ** Copyright 2011, Oliver Tappe, zooey@hirschkaefer.de. All rights reserved.
3 ** Distributed under the terms of the MIT License.
4 */
5 
6 #include <errno.h>
7 #include <string.h>
8 #include <wchar.h>
9 
10 #include <errno_private.h>
11 #include <LocaleBackend.h>
12 #include <wchar_private.h>
13 
14 
15 //#define TRACE_WCSRTOMBS
16 #ifdef TRACE_WCSRTOMBS
17 #	include <OS.h>
18 #	define TRACE(x) debug_printf x
19 #else
20 #	define TRACE(x) ;
21 #endif
22 
23 
24 using BPrivate::Libroot::gLocaleBackend;
25 
26 
27 extern "C" size_t
28 __wcsnrtombs(char* dst, const wchar_t** src, size_t nwc, size_t len,
29 	mbstate_t* ps)
30 {
31 	TRACE(("wcsnrtombs(%p, %p, %lu, %lu) - lb:%p\n", dst, *src, nwc, len,
32 		gLocaleBackend));
33 
34 	if (ps == NULL) {
35 		static mbstate_t internalMbState;
36 		ps = &internalMbState;
37 	}
38 
39 	if (gLocaleBackend == NULL) {
40 		/*
41 		 * The POSIX locale is active. Since the POSIX locale only contains
42 		 * chars 0-127 and those ASCII chars are compatible with the UTF32
43 		 * values used in wint_t, we can just copy the codepoint values.
44 		 */
45 		size_t count = 0;
46 		const wchar_t* srcEnd = *src + nwc;
47 		if (dst == NULL) {
48 			// only count number of required wide characters
49 			const wchar_t* wcSrc = *src;
50 			for (; wcSrc < srcEnd; ++wcSrc, ++count) {
51 				if (*wcSrc < 0) {
52 					// char is non-ASCII
53 					__set_errno(EILSEQ);
54 					count = (size_t)-1;
55 					break;
56 				}
57 				if (*wcSrc == 0) {
58 					memset(ps, 0, sizeof(mbstate_t));
59 					break;
60 				}
61 			}
62 		} else {
63 			// "convert" the characters
64 			for (; *src < srcEnd && count < len; ++*src, ++count) {
65 				if (**src < 0) {
66 					// char is non-ASCII
67 					__set_errno(EILSEQ);
68 					count = (size_t)-1;
69 					break;
70 				}
71 				*dst++ = (char)**src;
72 				if (**src == 0) {
73 					memset(ps, 0, sizeof(mbstate_t));
74 					*src = NULL;
75 					break;
76 				}
77 			}
78 		}
79 
80 		TRACE(("wcsnrtombs returns %lx and src %p\n", count, *src));
81 
82 		return count;
83 	}
84 
85 	size_t result = 0;
86 	status_t status = gLocaleBackend->WcharStringToMultibyte(dst, len, src, nwc,
87 		ps, result);
88 
89 	if (status == B_BAD_DATA) {
90 		TRACE(("wcsnrtomb(): setting errno to EILSEQ\n"));
91 		__set_errno(EILSEQ);
92 		result = (size_t)-1;
93 	} else if (status != B_OK) {
94 		TRACE(("wcsnrtomb(): setting errno to EINVAL (status: %lx)\n", status));
95 		__set_errno(EINVAL);
96 		result = (size_t)-1;
97 	}
98 
99 	TRACE(("wcsnrtombs returns %lx and src %p\n", result, *src));
100 
101 	return result;
102 }
103 
104 
105 B_DEFINE_WEAK_ALIAS(__wcsnrtombs, wcsnrtombs);
106 
107 
108 extern "C" size_t
109 __wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* ps)
110 {
111 	if (ps == NULL) {
112 		static mbstate_t internalMbState;
113 		ps = &internalMbState;
114 	}
115 
116 	return __wcsnrtombs(dst, src, __wcslen(*src) + 1, len, ps);
117 }
118 
119 
120 B_DEFINE_WEAK_ALIAS(__wcsrtombs, wcsrtombs);
121