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
24using BPrivate::Libroot::GetCurrentLocaleBackend;
25using BPrivate::Libroot::LocaleBackend;
26
27
28extern "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
108B_DEFINE_WEAK_ALIAS(__wcsnrtombs, wcsnrtombs);
109
110
111extern "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
123B_DEFINE_WEAK_ALIAS(__wcsrtombs, wcsrtombs);
124