xref: /haiku/src/system/libroot/posix/wchar/mbsrtowcs.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
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 
13 
14 //#define TRACE_MBSRTOWCS
15 #ifdef TRACE_MBSRTOWCS
16 #	include <OS.h>
17 #	define TRACE(x) debug_printf x
18 #else
19 #	define TRACE(x) ;
20 #endif
21 
22 
23 using BPrivate::Libroot::gLocaleBackend;
24 
25 
26 extern "C" size_t
27 __mbsnrtowcs(wchar_t* dst, const char** src, size_t nmc, size_t len,
28 	mbstate_t* ps)
29 {
30 	TRACE(("mbsnrtowcs(%p, %p, %lu, %lu) - lb:%p\n", dst, *src, nmc, len,
31 		gLocaleBackend));
32 
33 	if (ps == NULL) {
34 		static mbstate_t internalMbState;
35 		ps = &internalMbState;
36 	}
37 
38 	if (gLocaleBackend == NULL) {
39 		/*
40 		 * The POSIX locale is active. Since the POSIX locale only contains
41 		 * chars 0-127 and those ASCII chars are compatible with the UTF32
42 		 * values used in wint_t, we can just copy the bytes.
43 		 */
44 		size_t count = 0;
45 		const char* srcEnd = *src + nmc;
46 		if (dst == NULL) {
47 			// only count number of required wide characters
48 			const char* mbSrc = *src;
49 			for (; mbSrc < srcEnd; ++mbSrc, ++count) {
50 				if (*mbSrc < 0) {
51 					// char is non-ASCII
52 					__set_errno(EILSEQ);
53 					count = (size_t)-1;
54 					break;
55 				}
56 				if (*mbSrc == 0) {
57 					memset(ps, 0, sizeof(mbstate_t));
58 					break;
59 				}
60 			}
61 		} else {
62 			// "convert" the characters
63 			for (; *src < srcEnd && count < len; ++*src, ++count) {
64 				if (**src < 0) {
65 					// char is non-ASCII
66 					__set_errno(EILSEQ);
67 					count = (size_t)-1;
68 					break;
69 				}
70 				*dst++ = (wchar_t)**src;
71 				if (**src == 0) {
72 					memset(ps, 0, sizeof(mbstate_t));
73 					*src = NULL;
74 					break;
75 				}
76 			}
77 		}
78 
79 		TRACE(("mbsnrtowcs returns %lx and src %p\n", count, *src));
80 
81 		return count;
82 	}
83 
84 	size_t result = 0;
85 	status_t status = gLocaleBackend->MultibyteStringToWchar(dst, len, src, nmc,
86 		ps, result);
87 
88 	if (status == B_BAD_DATA) {
89 		TRACE(("mbsnrtowc(): setting errno to EILSEQ\n"));
90 		__set_errno(EILSEQ);
91 		result = (size_t)-1;
92 	} else if (status != B_OK) {
93 		TRACE(("mbsnrtowc(): setting errno to EINVAL (status: %lx)\n", status));
94 		__set_errno(EINVAL);
95 		result = (size_t)-1;
96 	}
97 
98 	TRACE(("mbsnrtowcs returns %lx and src %p\n", result, *src));
99 
100 	return result;
101 }
102 
103 
104 B_DEFINE_WEAK_ALIAS(__mbsnrtowcs, mbsnrtowcs);
105 
106 
107 extern "C" size_t
108 __mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps)
109 {
110 	if (ps == NULL) {
111 		static mbstate_t internalMbState;
112 		ps = &internalMbState;
113 	}
114 
115 	size_t srcLen = gLocaleBackend == NULL ? strlen(*src) + 1 : (size_t)-1;
116 
117 	return __mbsnrtowcs(dst, src, srcLen, len, ps);
118 }
119 
120 
121 B_DEFINE_WEAK_ALIAS(__mbsrtowcs, mbsrtowcs);
122