1119998Sgad/*
2119998Sgad** Copyright 2011, Oliver Tappe, zooey@hirschkaefer.de. All rights reserved.
3119998Sgad** Distributed under the terms of the MIT License.
4119998Sgad*/
5119998Sgad
6119998Sgad#include <errno.h>
7119998Sgad#include <string.h>
8119998Sgad#include <wchar.h>
9119998Sgad
10119998Sgad#include <errno_private.h>
11119998Sgad#include <LocaleBackend.h>
12119998Sgad
13119998Sgad
14119998Sgad//#define TRACE_MBRTOWC
15119998Sgad#ifdef TRACE_MBRTOWC
16119998Sgad#	include <OS.h>
17119998Sgad#	define TRACE(x) debug_printf x
18119998Sgad#else
19119998Sgad#	define TRACE(x) ;
20119998Sgad#endif
21119998Sgad
22119998Sgad
23119998Sgadusing BPrivate::Libroot::GetCurrentLocaleBackend;
24119998Sgadusing BPrivate::Libroot::LocaleBackend;
25119998Sgad
26119998Sgad
27119998Sgadextern "C" size_t
28119998Sgad__mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t* ps)
29119998Sgad{
30119998Sgad	if (ps == NULL) {
31119998Sgad		static mbstate_t internalMbState;
32119998Sgad		ps = &internalMbState;
33119998Sgad	}
34119998Sgad
35119998Sgad	if (s == NULL)
36119998Sgad		return __mbrtowc(NULL, "", 1, ps);
37120361Sgad	if (n == 0)
38120361Sgad		return (size_t)-2;
39120361Sgad
40120361Sgad	LocaleBackend* backend = GetCurrentLocaleBackend();
41119998Sgad
42119998Sgad	if (backend == NULL) {
43119998Sgad		if (*s == '\0') {
44119998Sgad			memset(ps, 0, sizeof(mbstate_t));
45119998Sgad
46119998Sgad			if (pwc != NULL)
47119998Sgad				*pwc = 0;
48119998Sgad
49119998Sgad			return 0;
50120361Sgad		}
51119998Sgad
52119998Sgad		/*
53119998Sgad		 * The POSIX locale is active. Since the POSIX locale only contains
54119998Sgad		 * chars 0-127 and those ASCII chars are compatible with the UTF32
55120361Sgad		 * values used in wint_t, we can just return the byte.
56120361Sgad		 */
57120361Sgad
58120361Sgad		if (*s < 0) {
59120361Sgad			// char is non-ASCII
60120361Sgad			__set_errno(EILSEQ);
61120361Sgad			return (size_t)-1;
62120361Sgad		}
63120361Sgad
64120361Sgad		if (pwc != NULL)
65120361Sgad			*pwc = *s;
66120361Sgad
67120361Sgad		return 1;
68120361Sgad	}
69120361Sgad
70120361Sgad	size_t lengthUsed;
71120361Sgad	status_t status = backend->MultibyteToWchar(pwc, s, n, ps, lengthUsed);
72120361Sgad
73120361Sgad	if (status == B_BAD_INDEX)
74120361Sgad		return (size_t)-2;
75120361Sgad
76120361Sgad	if (status == B_BAD_DATA) {
77120361Sgad		TRACE(("mbrtowc(): setting errno to EILSEQ\n"));
78120361Sgad		__set_errno(EILSEQ);
79120361Sgad		return (size_t)-1;
80120361Sgad	}
81120361Sgad
82120046Sgad	if (status != B_OK) {
83120361Sgad		TRACE(("mbrtowc(): setting errno to EINVAL (status: %lx)\n", status));
84120361Sgad		__set_errno(EINVAL);
85120046Sgad		return (size_t)-1;
86120046Sgad	}
87120046Sgad
88120046Sgad	return lengthUsed;
89120046Sgad}
90120046Sgad
91120046Sgad
92120046SgadB_DEFINE_WEAK_ALIAS(__mbrtowc, mbrtowc);
93120046Sgad