xref: /haiku/src/system/libroot/posix/wchar/mbrtowc.cpp (revision 5cbb772a4d8c89f84605c47b42982d41ff08749b)
1cc5eca75SOliver Tappe /*
2cc5eca75SOliver Tappe ** Copyright 2011, Oliver Tappe, zooey@hirschkaefer.de. All rights reserved.
347a21c5cSAugustin Cavalier ** Distributed under the terms of the MIT License.
4cc5eca75SOliver Tappe */
5cc5eca75SOliver Tappe 
6cc5eca75SOliver Tappe #include <errno.h>
7cc5eca75SOliver Tappe #include <string.h>
8cc5eca75SOliver Tappe #include <wchar.h>
9cc5eca75SOliver Tappe 
10ae901935SOliver Tappe #include <errno_private.h>
11d7965519SOliver Tappe #include <LocaleBackend.h>
12cc5eca75SOliver Tappe 
13cc5eca75SOliver Tappe 
1459e43b2aSOliver Tappe //#define TRACE_MBRTOWC
1559e43b2aSOliver Tappe #ifdef TRACE_MBRTOWC
1659e43b2aSOliver Tappe #	include <OS.h>
1759e43b2aSOliver Tappe #	define TRACE(x) debug_printf x
1859e43b2aSOliver Tappe #else
1959e43b2aSOliver Tappe #	define TRACE(x) ;
2059e43b2aSOliver Tappe #endif
2159e43b2aSOliver Tappe 
2259e43b2aSOliver Tappe 
23d338200eSTrung Nguyen using BPrivate::Libroot::GetCurrentLocaleBackend;
24d338200eSTrung Nguyen using BPrivate::Libroot::LocaleBackend;
25cc5eca75SOliver Tappe 
26cc5eca75SOliver Tappe 
27cc5eca75SOliver Tappe extern "C" size_t
__mbrtowc(wchar_t * pwc,const char * s,size_t n,mbstate_t * ps)28cc5eca75SOliver Tappe __mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t* ps)
29cc5eca75SOliver Tappe {
30cc5eca75SOliver Tappe 	if (ps == NULL) {
31cc5eca75SOliver Tappe 		static mbstate_t internalMbState;
32cc5eca75SOliver Tappe 		ps = &internalMbState;
33cc5eca75SOliver Tappe 	}
34cc5eca75SOliver Tappe 
35cc5eca75SOliver Tappe 	if (s == NULL)
36cc5eca75SOliver Tappe 		return __mbrtowc(NULL, "", 1, ps);
37*5cbb772aSAugustin Cavalier 	if (n == 0)
38*5cbb772aSAugustin Cavalier 		return (size_t)-2;
39cc5eca75SOliver Tappe 
40d338200eSTrung Nguyen 	LocaleBackend* backend = GetCurrentLocaleBackend();
41d338200eSTrung Nguyen 
42d338200eSTrung Nguyen 	if (backend == NULL) {
43cc5eca75SOliver Tappe 		if (*s == '\0') {
44cc5eca75SOliver Tappe 			memset(ps, 0, sizeof(mbstate_t));
45cc5eca75SOliver Tappe 
46cc5eca75SOliver Tappe 			if (pwc != NULL)
47cc5eca75SOliver Tappe 				*pwc = 0;
48cc5eca75SOliver Tappe 
49cc5eca75SOliver Tappe 			return 0;
50cc5eca75SOliver Tappe 		}
51cc5eca75SOliver Tappe 
52cc5eca75SOliver Tappe 		/*
53cc5eca75SOliver Tappe 		 * The POSIX locale is active. Since the POSIX locale only contains
54cc5eca75SOliver Tappe 		 * chars 0-127 and those ASCII chars are compatible with the UTF32
55cc5eca75SOliver Tappe 		 * values used in wint_t, we can just return the byte.
56cc5eca75SOliver Tappe 		 */
57cc5eca75SOliver Tappe 
58cc5eca75SOliver Tappe 		if (*s < 0) {
59cc5eca75SOliver Tappe 			// char is non-ASCII
60ae901935SOliver Tappe 			__set_errno(EILSEQ);
61cc5eca75SOliver Tappe 			return (size_t)-1;
62cc5eca75SOliver Tappe 		}
63cc5eca75SOliver Tappe 
64cc5eca75SOliver Tappe 		if (pwc != NULL)
65cc5eca75SOliver Tappe 			*pwc = *s;
66cc5eca75SOliver Tappe 
67cc5eca75SOliver Tappe 		return 1;
68cc5eca75SOliver Tappe 	}
69cc5eca75SOliver Tappe 
70cc5eca75SOliver Tappe 	size_t lengthUsed;
71d338200eSTrung Nguyen 	status_t status = backend->MultibyteToWchar(pwc, s, n, ps, lengthUsed);
72cc5eca75SOliver Tappe 
73cc5eca75SOliver Tappe 	if (status == B_BAD_INDEX)
74cc5eca75SOliver Tappe 		return (size_t)-2;
75cc5eca75SOliver Tappe 
76cc5eca75SOliver Tappe 	if (status == B_BAD_DATA) {
7759e43b2aSOliver Tappe 		TRACE(("mbrtowc(): setting errno to EILSEQ\n"));
78ae901935SOliver Tappe 		__set_errno(EILSEQ);
79cc5eca75SOliver Tappe 		return (size_t)-1;
80cc5eca75SOliver Tappe 	}
81cc5eca75SOliver Tappe 
82cc5eca75SOliver Tappe 	if (status != B_OK) {
8359e43b2aSOliver Tappe 		TRACE(("mbrtowc(): setting errno to EINVAL (status: %lx)\n", status));
84ae901935SOliver Tappe 		__set_errno(EINVAL);
85cc5eca75SOliver Tappe 		return (size_t)-1;
86cc5eca75SOliver Tappe 	}
87cc5eca75SOliver Tappe 
88cc5eca75SOliver Tappe 	return lengthUsed;
89cc5eca75SOliver Tappe }
90cc5eca75SOliver Tappe 
91cc5eca75SOliver Tappe 
92cc5eca75SOliver Tappe B_DEFINE_WEAK_ALIAS(__mbrtowc, mbrtowc);
93