xref: /haiku/src/system/libroot/posix/wchar/mbsrtowcs.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
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 
23 using BPrivate::Libroot::GetCurrentLocaleBackend;
24 using BPrivate::Libroot::LocaleBackend;
25 
26 
27 extern "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 
107 B_DEFINE_WEAK_ALIAS(__mbsnrtowcs, mbsnrtowcs);
108 
109 
110 extern "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 
125 B_DEFINE_WEAK_ALIAS(__mbsrtowcs, mbsrtowcs);
126