1/*
2** Copyright 2011, Oliver Tappe, zooey@hirschkaefer.de. All rights reserved.
3** Distributed under the terms of the Haiku 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::gLocaleBackend;
25
26
27extern "C" size_t
28__wcsnrtombs(char* dst, const wchar_t** src, size_t nwc, size_t len,
29	mbstate_t* ps)
30{
31	TRACE(("wcsnrtombs(%p, %p, %lu, %lu) - lb:%p\n", dst, *src, nwc, len,
32		gLocaleBackend));
33
34	if (ps == NULL) {
35		static mbstate_t internalMbState;
36		ps = &internalMbState;
37	}
38
39	if (gLocaleBackend == NULL) {
40		/*
41		 * The POSIX locale is active. Since the POSIX locale only contains
42		 * chars 0-127 and those ASCII chars are compatible with the UTF32
43		 * values used in wint_t, we can just copy the codepoint values.
44		 */
45		size_t count = 0;
46		const wchar_t* srcEnd = *src + nwc;
47		if (dst == NULL) {
48			// only count number of required wide characters
49			const wchar_t* wcSrc = *src;
50			for (; wcSrc < srcEnd; ++wcSrc, ++count) {
51				if (*wcSrc < 0) {
52					// char is non-ASCII
53					__set_errno(EILSEQ);
54					count = (size_t)-1;
55					break;
56				}
57				if (*wcSrc == 0) {
58					memset(ps, 0, sizeof(mbstate_t));
59					break;
60				}
61			}
62		} else {
63			// "convert" the characters
64			for (; *src < srcEnd && count < len; ++*src, ++count) {
65				if (**src < 0) {
66					// char is non-ASCII
67					__set_errno(EILSEQ);
68					count = (size_t)-1;
69					break;
70				}
71				*dst++ = (char)**src;
72				if (**src == 0) {
73					memset(ps, 0, sizeof(mbstate_t));
74					*src = NULL;
75					break;
76				}
77			}
78		}
79
80		TRACE(("wcsnrtombs returns %lx and src %p\n", count, *src));
81
82		return count;
83	}
84
85	size_t result = 0;
86	status_t status = gLocaleBackend->WcharStringToMultibyte(dst, len, src, nwc,
87		ps, result);
88
89	if (status == B_BAD_DATA) {
90		TRACE(("wcsnrtomb(): setting errno to EILSEQ\n"));
91		__set_errno(EILSEQ);
92		result = (size_t)-1;
93	} else if (status != B_OK) {
94		TRACE(("wcsnrtomb(): setting errno to EINVAL (status: %lx)\n", status));
95		__set_errno(EINVAL);
96		result = (size_t)-1;
97	}
98
99	TRACE(("wcsnrtombs returns %lx and src %p\n", result, *src));
100
101	return result;
102}
103
104
105extern "C"
106B_DEFINE_WEAK_ALIAS(__wcsnrtombs, wcsnrtombs);
107
108
109extern "C" size_t
110__wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* ps)
111{
112	if (ps == NULL) {
113		static mbstate_t internalMbState;
114		ps = &internalMbState;
115	}
116
117	return __wcsnrtombs(dst, src, __wcslen(*src) + 1, len, ps);
118}
119
120
121extern "C"
122B_DEFINE_WEAK_ALIAS(__wcsrtombs, wcsrtombs);
123