diff --git a/libc/bionic/wchar.cpp b/libc/bionic/wchar.cpp index 50a387535..8d5645857 100644 --- a/libc/bionic/wchar.cpp +++ b/libc/bionic/wchar.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -156,8 +157,8 @@ int mbsinit(const mbstate_t* /*ps*/) { return 1; } -size_t mbrlen(const char* /*s*/, size_t n, mbstate_t* /*ps*/) { - return (n != 0); +size_t mbrlen(const char* s, size_t n, mbstate_t* /*ps*/) { + return (n == 0 || s[0] == 0) ? 0 : 1; } size_t mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t* /*ps*/) { @@ -217,13 +218,26 @@ wint_t ungetwc(wint_t wc, FILE* stream) { return ungetc(static_cast(wc), stream); } -size_t wcrtomb(char* s, wchar_t /*wc*/, mbstate_t* /*ps*/) { - if (s != NULL) { - *s = 1; +int wctomb(char* s, wchar_t wc) { + if (s == NULL) { + return 0; + } + if (wc <= 0xff) { + *s = static_cast(wc); + } else { + *s = '?'; } return 1; } +size_t wcrtomb(char* s, wchar_t wc, mbstate_t* /*ps*/) { + if (s == NULL) { + char buf[MB_LEN_MAX]; + return wctomb(buf, L'\0'); + } + return wctomb(s, wc); +} + size_t wcsftime(wchar_t* wcs, size_t maxsize, const wchar_t* format, const struct tm* timptr) { return strftime(reinterpret_cast(wcs), maxsize, reinterpret_cast(format), timptr); } diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index 9b7e6d16a..5dbcb3d7d 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -151,7 +151,6 @@ extern lldiv_t lldiv(long long, long long); extern const char* getprogname(void); extern void setprogname(const char*); -#if 1 /* MISSING FROM BIONIC - ENABLED FOR STLPort and libstdc++-v3 */ /* make STLPort happy */ extern int mblen(const char *, size_t); extern size_t mbstowcs(wchar_t *, const char *, size_t); @@ -160,7 +159,6 @@ extern int mbtowc(wchar_t *, const char *, size_t); /* Likewise, make libstdc++-v3 happy. */ extern int wctomb(char *, wchar_t); extern size_t wcstombs(char *, const wchar_t *, size_t); -#endif /* MISSING */ #define MB_CUR_MAX 1 diff --git a/libc/include/wchar.h b/libc/include/wchar.h index 32cf12763..89c6fb603 100644 --- a/libc/include/wchar.h +++ b/libc/include/wchar.h @@ -36,13 +36,6 @@ #include #include -/* IMPORTANT: Any code that relies on wide character support is essentially - * non-portable and/or broken. the only reason this header exist - * is because I'm really a nice guy. However, I'm not nice enough - * to provide you with a real implementation. instead wchar_t == char - * and all wc functions are stubs to their "normal" equivalent... - */ - __BEGIN_DECLS typedef __WINT_TYPE__ wint_t; @@ -150,12 +143,11 @@ extern int wscanf(const wchar_t *, ...); extern size_t wcslcat(wchar_t*, const wchar_t*, size_t); extern size_t wcslcpy(wchar_t*, const wchar_t*, size_t); -/* No really supported. These are just for making libstdc++-v3 happy. */ typedef void *wctrans_t; -extern wint_t towctrans(wint_t, wctrans_t); -extern wctrans_t wctrans (const char *); +extern wint_t towctrans(wint_t, wctrans_t); +extern wctrans_t wctrans(const char*); -#if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L +#if __POSIX_VISIBLE >= 200809 wchar_t* wcsdup(const wchar_t*); size_t wcsnlen(const wchar_t*, size_t); #endif diff --git a/tests/Android.mk b/tests/Android.mk index 7482ebc90..e8ee687da 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -82,6 +82,7 @@ libBionicStandardTests_src_files := \ system_properties_test.cpp \ time_test.cpp \ unistd_test.cpp \ + wchar_test.cpp \ libBionicStandardTests_cflags := \ $(test_cflags) \ diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp new file mode 100644 index 000000000..20566f26a --- /dev/null +++ b/tests/wchar_test.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +TEST(wchar, sizeof_wchar_t) { + EXPECT_EQ(4U, sizeof(wchar_t)); + EXPECT_EQ(4U, sizeof(wint_t)); +} + +TEST(wchar, mbrlen) { + char bytes[] = { 'h', 'e', 'l', 'l', 'o', '\0' }; + EXPECT_EQ(0U, mbrlen(&bytes[0], 0, NULL)); + EXPECT_EQ(1U, mbrlen(&bytes[0], 1, NULL)); + + EXPECT_EQ(1U, mbrlen(&bytes[4], 1, NULL)); + EXPECT_EQ(0U, mbrlen(&bytes[5], 1, NULL)); +} + +TEST(wchar, wctomb_wcrtomb) { + // wctomb and wcrtomb behave differently when s == NULL. + EXPECT_EQ(0, wctomb(NULL, L'h')); + EXPECT_EQ(0, wctomb(NULL, L'\0')); + EXPECT_EQ(1U, wcrtomb(NULL, L'\0', NULL)); + EXPECT_EQ(1U, wcrtomb(NULL, L'h', NULL)); + + char bytes[MB_LEN_MAX]; + + // wctomb and wcrtomb behave similarly for the null wide character. + EXPECT_EQ(1, wctomb(bytes, L'\0')); + EXPECT_EQ(1U, wcrtomb(bytes, L'\0', NULL)); + + // ...and for regular characters. + bytes[0] = 'x'; + EXPECT_EQ(1, wctomb(bytes, L'h')); + EXPECT_EQ('h', bytes[0]); + + bytes[0] = 'x'; + EXPECT_EQ(1U, wcrtomb(bytes, L'h', NULL)); + EXPECT_EQ('h', bytes[0]); +}