xref: /haiku/src/system/libroot/posix/wchar/wcsrtombs.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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::GetCurrentLocaleBackend;
25 using BPrivate::Libroot::LocaleBackend;
26 
27 
28 extern "C" size_t
29 __wcsnrtombs(char* dst, const wchar_t** src, size_t nwc, size_t len,
30 	mbstate_t* ps)
31 {
32 	LocaleBackend* backend = GetCurrentLocaleBackend();
33 
34 	TRACE(("wcsnrtombs(%p, %p, %lu, %lu) - lb:%p\n", dst, *src, nwc, len,
35 		backend));
36 
37 	if (ps == NULL) {
38 		static mbstate_t internalMbState;
39 		ps = &internalMbState;
40 	}
41 
42 	if (backend == NULL) {
43 		/*
44 		 * The POSIX locale is active. Since the POSIX locale only contains
45 		 * chars 0-127 and those ASCII chars are compatible with the UTF32
46 		 * values used in wint_t, we can just copy the codepoint values.
47 		 */
48 		size_t count = 0;
49 		const wchar_t* srcEnd = *src + nwc;
50 		if (dst == NULL) {
51 			// only count number of required wide characters
52 			const wchar_t* wcSrc = *src;
53 			for (; wcSrc < srcEnd; ++wcSrc, ++count) {
54 				if (*wcSrc < 0) {
55 					// char is non-ASCII
56 					__set_errno(EILSEQ);
57 					count = (size_t)-1;
58 					break;
59 				}
60 				if (*wcSrc == 0) {
61 					memset(ps, 0, sizeof(mbstate_t));
62 					break;
63 				}
64 			}
65 		} else {
66 			// "convert" the characters
67 			for (; *src < srcEnd && count < len; ++*src, ++count) {
68 				if (**src < 0) {
69 					// char is non-ASCII
70 					__set_errno(EILSEQ);
71 					count = (size_t)-1;
72 					break;
73 				}
74 				*dst++ = (char)**src;
75 				if (**src == 0) {
76 					memset(ps, 0, sizeof(mbstate_t));
77 					*src = NULL;
78 					break;
79 				}
80 			}
81 		}
82 
83 		TRACE(("wcsnrtombs returns %lx and src %p\n", count, *src));
84 
85 		return count;
86 	}
87 
88 	size_t result = 0;
89 	status_t status = backend->WcharStringToMultibyte(dst, len, src, nwc,
90 		ps, result);
91 
92 	if (status == B_BAD_DATA) {
93 		TRACE(("wcsnrtomb(): setting errno to EILSEQ\n"));
94 		__set_errno(EILSEQ);
95 		result = (size_t)-1;
96 	} else if (status != B_OK) {
97 		TRACE(("wcsnrtomb(): setting errno to EINVAL (status: %lx)\n", status));
98 		__set_errno(EINVAL);
99 		result = (size_t)-1;
100 	}
101 
102 	TRACE(("wcsnrtombs returns %lx and src %p\n", result, *src));
103 
104 	return result;
105 }
106 
107 
108 B_DEFINE_WEAK_ALIAS(__wcsnrtombs, wcsnrtombs);
109 
110 
111 extern "C" size_t
112 __wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* ps)
113 {
114 	if (ps == NULL) {
115 		static mbstate_t internalMbState;
116 		ps = &internalMbState;
117 	}
118 
119 	return __wcsnrtombs(dst, src, __wcslen(*src) + 1, len, ps);
120 }
121 
122 
123 B_DEFINE_WEAK_ALIAS(__wcsrtombs, wcsrtombs);
124