OSDN Git Service

Implement wctomb(3) for ltrace.
authorElliott Hughes <enh@google.com>
Sat, 5 Apr 2014 00:34:51 +0000 (17:34 -0700)
committerElliott Hughes <enh@google.com>
Mon, 7 Apr 2014 21:29:28 +0000 (14:29 -0700)
This is an implementation in the style of the rest: char == byte.

We might want to come back and implement UTF-8, but this is enough for ltrace.

Bug: 13747066
Change-Id: Ib2b63609c9014fdef9a8491e067467c4fc5ae3cc

libc/bionic/wchar.cpp
libc/include/stdlib.h
libc/include/wchar.h
tests/Android.mk
tests/wchar_test.cpp [new file with mode: 0644]

index 50a3875..8d56458 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <ctype.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
@@ -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<char>(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<char>(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<char*>(wcs), maxsize, reinterpret_cast<const char*>(format), timptr);
 }
index 9b7e6d1..5dbcb3d 100644 (file)
@@ -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
 
index 32cf127..89c6fb6 100644 (file)
 #include <time.h>
 #include <malloc.h>
 
-/* 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
index 7482ebc..e8ee687 100644 (file)
@@ -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 (file)
index 0000000..20566f2
--- /dev/null
@@ -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 <gtest/gtest.h>
+
+#include <limits.h>
+#include <wchar.h>
+
+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]);
+}