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