Fix <wctype.h>.

* Fix the return type of towlower_l/towupper_l.
* Implement wctrans/wctrans_l/towctrans/towctrans_l.
* Move declarations that POSIX says are available from both <wchar.h> and
  <wctype.h> to <bits/wctype.h> and include from both POSIX headers.
* Write the missing tests.

Change-Id: I3221da5f3d7e8a2fb0a7619dc724de45f7b55398
diff --git a/libc/bionic/wctype.cpp b/libc/bionic/wctype.cpp
index f2d7861..05e9c90 100644
--- a/libc/bionic/wctype.cpp
+++ b/libc/bionic/wctype.cpp
@@ -26,11 +26,13 @@
  * SUCH DAMAGE.
  */
 
+#include <wctype.h>
+
 #include <ctype.h>
+#include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
-#include <wctype.h>
 
 // TODO: these only work for the ASCII range; rewrite to dlsym icu4c? http://b/14499654
 
@@ -85,8 +87,8 @@
 wint_t towlower(wint_t wc) { return tolower(wc); }
 wint_t towupper(wint_t wc) { return toupper(wc); }
 
-int towupper_l(int c, locale_t) { return towupper(c); }
-int towlower_l(int c, locale_t) { return towlower(c); }
+wint_t towupper_l(int c, locale_t) { return towupper(c); }
+wint_t towlower_l(int c, locale_t) { return towlower(c); }
 
 wctype_t wctype(const char* property) {
   static const char* const  properties[WC_TYPE_MAX] = {
@@ -109,3 +111,27 @@
 int wcwidth(wchar_t wc) {
   return (wc > 0);
 }
+
+static wctrans_t wctrans_tolower = wctrans_t(1);
+static wctrans_t wctrans_toupper = wctrans_t(2);
+
+wctrans_t wctrans(const char* name) {
+  if (strcmp(name, "tolower") == 0) return wctrans_tolower;
+  if (strcmp(name, "toupper") == 0) return wctrans_toupper;
+  return 0;
+}
+
+wctrans_t wctrans_l(const char* name, locale_t) {
+  return wctrans(name);
+}
+
+wint_t towctrans(wint_t c, wctrans_t t) {
+  if (t == wctrans_tolower) return towlower(c);
+  if (t == wctrans_toupper) return towupper(c);
+  errno = EINVAL;
+  return 0;
+}
+
+wint_t towctrans_l(wint_t c, wctrans_t t, locale_t) {
+  return towctrans(c, t);
+}
diff --git a/libc/include/bits/wctype.h b/libc/include/bits/wctype.h
new file mode 100644
index 0000000..8f32aba
--- /dev/null
+++ b/libc/include/bits/wctype.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BITS_WCTYPE_H_
+#define _BITS_WCTYPE_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef __WINT_TYPE__ wint_t;
+
+int iswalnum(wint_t);
+int iswalpha(wint_t);
+int iswblank(wint_t);
+int iswcntrl(wint_t);
+int iswdigit(wint_t);
+int iswgraph(wint_t);
+int iswlower(wint_t);
+int iswprint(wint_t);
+int iswpunct(wint_t);
+int iswspace(wint_t);
+int iswupper(wint_t);
+int iswxdigit(wint_t);
+
+wint_t towlower(wint_t);
+wint_t towupper(wint_t);
+
+typedef long wctype_t;
+wctype_t wctype(const char*);
+int iswctype(wint_t, wctype_t);
+
+typedef const void* wctrans_t;
+wint_t towctrans(wint_t, wctrans_t);
+wctrans_t wctrans(const char*);
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/wchar.h b/libc/include/wchar.h
index f65c988..625097e 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -37,10 +37,10 @@
 #include <xlocale.h>
 
 #include <bits/wchar_limits.h>
+#include <bits/wctype.h>
 
 __BEGIN_DECLS
 
-typedef __WINT_TYPE__  wint_t;
 typedef struct {
   uint8_t __seq[4];
 #ifdef __LP64__
@@ -65,26 +65,11 @@
     WC_TYPE_MAX
 };
 
-typedef long wctype_t;
-
 #define  WEOF        ((wint_t)(-1))
 
 extern wint_t            btowc(int);
 extern int               fwprintf(FILE *, const wchar_t *, ...);
 extern int               fwscanf(FILE *, const wchar_t *, ...);
-extern int               iswalnum(wint_t);
-extern int               iswalpha(wint_t);
-extern int               iswblank(wint_t);
-extern int               iswcntrl(wint_t);
-extern int               iswdigit(wint_t);
-extern int               iswgraph(wint_t);
-extern int               iswlower(wint_t);
-extern int               iswprint(wint_t);
-extern int               iswpunct(wint_t);
-extern int               iswspace(wint_t);
-extern int               iswupper(wint_t);
-extern int               iswxdigit(wint_t);
-extern int               iswctype(wint_t, wctype_t);
 extern wint_t            fgetwc(FILE *);
 extern wchar_t          *fgetws(wchar_t *, int, FILE *);
 extern wint_t            fputwc(wchar_t, FILE *);
@@ -101,8 +86,6 @@
 extern wint_t            putwchar(wchar_t);
 extern int               swprintf(wchar_t *, size_t, const wchar_t *, ...);
 extern int               swscanf(const wchar_t *, const wchar_t *, ...);
-extern wint_t            towlower(wint_t);
-extern wint_t            towupper(wint_t);
 extern wint_t            ungetwc(wint_t, FILE *);
 extern int vfwprintf(FILE*, const wchar_t*, va_list);
 extern int vfwscanf(FILE*, const wchar_t*, va_list);
@@ -145,7 +128,6 @@
 extern int               wcswidth(const wchar_t *, size_t);
 extern size_t            wcsxfrm(wchar_t *, const wchar_t *, size_t);
 extern int               wctob(wint_t);
-extern wctype_t          wctype(const char *);
 extern int               wcwidth(wchar_t);
 extern wchar_t          *wmemchr(const wchar_t *, wchar_t, size_t);
 extern int               wmemcmp(const wchar_t *, const wchar_t *, size_t);
@@ -168,10 +150,6 @@
 extern size_t wcslcat(wchar_t*, const wchar_t*, size_t);
 extern size_t wcslcpy(wchar_t*, const wchar_t*, size_t);
 
-typedef void *wctrans_t;
-extern wint_t towctrans(wint_t, wctrans_t) __UNAVAILABLE;
-extern wctrans_t wctrans(const char*) __UNAVAILABLE;
-
 #if __POSIX_VISIBLE >= 200809
 FILE* open_wmemstream(wchar_t**, size_t*);
 wchar_t* wcsdup(const wchar_t*);
diff --git a/libc/include/wctype.h b/libc/include/wctype.h
index 1a4a05e..12ef7cd 100644
--- a/libc/include/wctype.h
+++ b/libc/include/wctype.h
@@ -31,25 +31,31 @@
 
 #include <wchar.h>
 
+#include <bits/wctype.h>
+
 __BEGIN_DECLS
 
-extern int iswalnum_l(wint_t, locale_t);
-extern int iswalpha_l(wint_t, locale_t);
-extern int iswblank_l(wint_t, locale_t);
-extern int iswcntrl_l(wint_t, locale_t);
-extern int iswdigit_l(wint_t, locale_t);
-extern int iswgraph_l(wint_t, locale_t);
-extern int iswlower_l(wint_t, locale_t);
-extern int iswprint_l(wint_t, locale_t);
-extern int iswpunct_l(wint_t, locale_t);
-extern int iswspace_l(wint_t, locale_t);
-extern int iswupper_l(wint_t, locale_t);
-extern int iswxdigit_l(wint_t, locale_t);
-extern int towlower_l(int, locale_t);
-extern int towupper_l(int, locale_t);
+int iswalnum_l(wint_t, locale_t);
+int iswalpha_l(wint_t, locale_t);
+int iswblank_l(wint_t, locale_t);
+int iswcntrl_l(wint_t, locale_t);
+int iswdigit_l(wint_t, locale_t);
+int iswgraph_l(wint_t, locale_t);
+int iswlower_l(wint_t, locale_t);
+int iswprint_l(wint_t, locale_t);
+int iswpunct_l(wint_t, locale_t);
+int iswspace_l(wint_t, locale_t);
+int iswupper_l(wint_t, locale_t);
+int iswxdigit_l(wint_t, locale_t);
 
-extern int iswctype_l(wint_t, wctype_t, locale_t);
-extern wctype_t wctype_l(const char*, locale_t);
+wint_t towlower_l(int, locale_t);
+wint_t towupper_l(int, locale_t);
+
+wint_t towctrans_l(wint_t, wctrans_t, locale_t);
+wctrans_t wctrans_l(const char*, locale_t);
+
+wctype_t wctype_l(const char*, locale_t);
+int iswctype_l(wint_t, wctype_t, locale_t);
 
 __END_DECLS
 
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index a1373d8..6998cab 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1291,6 +1291,10 @@
     sigrelse;
     sigset;
     sync_file_range;
+    towctrans;
+    towctrans_l;
+    wctrans;
+    wctrans_l;
 } LIBC_N;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 4e69bf1..8628ed1 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1291,6 +1291,10 @@
     sigrelse;
     sigset;
     sync_file_range;
+    towctrans;
+    towctrans_l;
+    wctrans;
+    wctrans_l;
 } LIBC_N;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 7ea74a6..c853f73 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1213,6 +1213,10 @@
     sigrelse;
     sigset;
     sync_file_range;
+    towctrans;
+    towctrans_l;
+    wctrans;
+    wctrans_l;
 } LIBC_N;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 8d1a1f9..1ed2977 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1316,6 +1316,10 @@
     sigrelse;
     sigset;
     sync_file_range;
+    towctrans;
+    towctrans_l;
+    wctrans;
+    wctrans_l;
 } LIBC_N;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index aac1d8c..f42f5aa 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1275,6 +1275,10 @@
     sigrelse;
     sigset;
     sync_file_range;
+    towctrans;
+    towctrans_l;
+    wctrans;
+    wctrans_l;
 } LIBC_N;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index e514aa1..439c855 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1275,6 +1275,10 @@
     sigrelse;
     sigset;
     sync_file_range;
+    towctrans;
+    towctrans_l;
+    wctrans;
+    wctrans_l;
 } LIBC_N;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 7ea74a6..c853f73 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1213,6 +1213,10 @@
     sigrelse;
     sigset;
     sync_file_range;
+    towctrans;
+    towctrans_l;
+    wctrans;
+    wctrans_l;
 } LIBC_N;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index f14861d..b1ba988 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -1273,6 +1273,10 @@
     sigrelse;
     sigset;
     sync_file_range;
+    towctrans;
+    towctrans_l;
+    wctrans;
+    wctrans_l;
 } LIBC_N;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index f6b6ea1..bab1737 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1273,6 +1273,10 @@
     sigrelse;
     sigset;
     sync_file_range;
+    towctrans;
+    towctrans_l;
+    wctrans;
+    wctrans_l;
 } LIBC_N;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 7ea74a6..c853f73 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1213,6 +1213,10 @@
     sigrelse;
     sigset;
     sync_file_range;
+    towctrans;
+    towctrans_l;
+    wctrans;
+    wctrans_l;
 } LIBC_N;
 
 LIBC_PRIVATE {